Skip to content

Commit 71791ad

Browse files
authored
Add policy registry commands (#3806)
1 parent 62c2b7c commit 71791ad

File tree

28 files changed

+2088
-0
lines changed

28 files changed

+2088
-0
lines changed

private/buf/bufcli/errors.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ func NewPluginNameAlreadyExistsError(name string) error {
6060
return fmt.Errorf("a plugin named %q already exists", name)
6161
}
6262

63+
// NewPolicyNameAlreadyExistsError informs the user that a policy
64+
// with that name already exists.
65+
func NewPolicyNameAlreadyExistsError(name string) error {
66+
return fmt.Errorf("a policy named %q already exists", name)
67+
}
68+
6369
// NewOrganizationNotFoundError informs the user that an organization with
6470
// that name does not exist.
6571
func NewOrganizationNotFoundError(name string) error {
@@ -100,6 +106,12 @@ func NewPluginNotFoundError(name string) error {
100106
return fmt.Errorf("a plugin named %q does not exist", name)
101107
}
102108

109+
// NewPolicyNotFoundError informs the user that a plugin with
110+
// that name does not exist.
111+
func NewPolicyNotFoundError(name string) error {
112+
return fmt.Errorf("a plugin named %q does not exist", name)
113+
}
114+
103115
// NewInvalidRemoteError informs the user that the given remote is invalid.
104116
func NewInvalidRemoteError(err error, remote string, moduleFullName string) error {
105117
var connectErr *connect.Error

private/buf/bufcli/flags_args.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
modulev1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/module/v1"
2323
pluginv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/plugin/v1beta1"
24+
policyv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/policy/v1beta1"
2425
"buf.build/go/app"
2526
"buf.build/go/app/appcmd"
2627
"buf.build/go/standard/xstrings"
@@ -319,6 +320,21 @@ func VisibilityFlagToPluginVisibilityAllowUnspecified(visibility string) (plugin
319320
}
320321
}
321322

323+
// VisibilityFlagToPolicyVisibilityAllowUnspecified parses the given string as a pluginv1.PolicyVisibility
324+
// where an empty string will be parsed as unspecified.
325+
func VisibilityFlagToPolicyVisibilityAllowUnspecified(visibility string) (policyv1beta1.PolicyVisibility, error) {
326+
switch visibility {
327+
case publicVisibility:
328+
return policyv1beta1.PolicyVisibility_POLICY_VISIBILITY_PUBLIC, nil
329+
case privateVisibility:
330+
return policyv1beta1.PolicyVisibility_POLICY_VISIBILITY_PRIVATE, nil
331+
case "":
332+
return policyv1beta1.PolicyVisibility_POLICY_VISIBILITY_UNSPECIFIED, nil
333+
default:
334+
return 0, fmt.Errorf("invalid visibility: %s", visibility)
335+
}
336+
}
337+
322338
// ArchiveStatusFlagToModuleArchiveStatusFilter parses the given string as a modulev1.ListLabelsRequest_ArchiveFilter.
323339
func ArchiveStatusFlagToModuleArchiveStatusFilter(archiveStatus string) (modulev1.ListLabelsRequest_ArchiveFilter, error) {
324340
switch archiveStatus {
@@ -347,6 +363,20 @@ func ArchiveStatusFlagToPluginArchiveStatusFilter(archiveStatus string) (pluginv
347363
}
348364
}
349365

366+
// ArchiveStatusFlagToPolicyArchiveStatusFilter parses the given string as a pluginv1beta1.ListLabelsRequest_ArchiveFilter.
367+
func ArchiveStatusFlagToPolicyArchiveStatusFilter(archiveStatus string) (policyv1beta1.ListLabelsRequest_ArchiveFilter, error) {
368+
switch archiveStatus {
369+
case archivedArchiveStatus:
370+
return policyv1beta1.ListLabelsRequest_ARCHIVE_FILTER_ARCHIVED_ONLY, nil
371+
case unarchivedArchiveStatus:
372+
return policyv1beta1.ListLabelsRequest_ARCHIVE_FILTER_UNARCHIVED_ONLY, nil
373+
case allArchiveStatus:
374+
return policyv1beta1.ListLabelsRequest_ARCHIVE_FILTER_ALL, nil
375+
default:
376+
return 0, fmt.Errorf("invalid archive status: %s", archiveStatus)
377+
}
378+
}
379+
350380
// ValidateRequiredFlag validates that the required flag is set.
351381
func ValidateRequiredFlag[T comparable](flagName string, value T) error {
352382
var zero T

private/buf/bufprint/bufprint.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
modulev1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/module/v1"
2929
ownerv1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/owner/v1"
3030
pluginv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/plugin/v1beta1"
31+
policyv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/policy/v1beta1"
3132
"buf.build/go/standard/xstrings"
3233
"github.com/bufbuild/buf/private/bufpkg/bufparse"
3334
registryv1alpha1 "github.com/bufbuild/buf/private/gen/proto/go/buf/alpha/registry/v1alpha1"
@@ -271,6 +272,18 @@ func NewPluginEntity(plugin *pluginv1beta1.Plugin, pluginFullName bufparse.FullN
271272
}
272273
}
273274

275+
// NewPolicyEntity returns a new plugin entity to print.
276+
func NewPolicyEntity(policy *policyv1beta1.Policy, policyFullName bufparse.FullName) Entity {
277+
return outputPolicy{
278+
ID: policy.Id,
279+
Remote: policyFullName.Registry(),
280+
Owner: policyFullName.Owner(),
281+
Name: policyFullName.Name(),
282+
FullName: policyFullName.String(),
283+
CreateTime: policy.CreateTime.AsTime(),
284+
}
285+
}
286+
274287
// NewUserEntity returns a new user entity to print.
275288
func NewUserEntity(user *registryv1alpha1.User) Entity {
276289
return outputUser{
@@ -512,6 +525,19 @@ func (m outputPlugin) fullName() string {
512525
return m.FullName
513526
}
514527

528+
type outputPolicy struct {
529+
ID string `json:"id,omitempty"`
530+
Remote string `json:"remote,omitempty"`
531+
Owner string `json:"owner,omitempty"`
532+
Name string `json:"name,omitempty"`
533+
FullName string `json:"-" bufprint:"Name"`
534+
CreateTime time.Time `json:"create_time,omitempty" bufprint:"Create Time"`
535+
}
536+
537+
func (m outputPolicy) fullName() string {
538+
return m.FullName
539+
}
540+
515541
type outputUser struct {
516542
Username string `json:"username,omitempty"`
517543
FullName string `json:"-" bufprint:"Name"`

private/buf/cmd/buf/buf.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,18 @@ import (
101101
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/pluginlabel/pluginlabellist"
102102
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/pluginlabel/pluginlabelunarchive"
103103
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/plugin/pluginsettings/pluginsettingsupdate"
104+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policycommit/policycommitaddlabel"
105+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policycommit/policycommitinfo"
106+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policycommit/policycommitlist"
107+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policycommit/policycommitresolve"
108+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policycreate"
109+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policydelete"
110+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policyinfo"
111+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policylabel/policylabelarchive"
112+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policylabel/policylabelinfo"
113+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policylabel/policylabellist"
114+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policylabel/policylabelunarchive"
115+
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/policy/policysettings/policysettingsupdate"
104116
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrycc"
105117
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrylogin"
106118
"github.com/bufbuild/buf/private/buf/cmd/buf/command/registry/registrylogout"
@@ -335,6 +347,43 @@ func NewRootCommand(name string) *appcmd.Command {
335347
plugindelete.NewCommand("delete", builder),
336348
},
337349
},
350+
{
351+
Use: "policy",
352+
Short: "Manage BSR policies",
353+
Hidden: true,
354+
SubCommands: []*appcmd.Command{
355+
{
356+
Use: "commit",
357+
Short: "Manage a policy's commits",
358+
SubCommands: []*appcmd.Command{
359+
policycommitaddlabel.NewCommand("add-label", builder, ""),
360+
policycommitinfo.NewCommand("info", builder, ""),
361+
policycommitlist.NewCommand("list", builder, ""),
362+
policycommitresolve.NewCommand("resolve", builder, ""),
363+
},
364+
},
365+
{
366+
Use: "label",
367+
Short: "Manage a policy's labels",
368+
SubCommands: []*appcmd.Command{
369+
policylabelarchive.NewCommand("archive", builder, ""),
370+
policylabelinfo.NewCommand("info", builder, ""),
371+
policylabellist.NewCommand("list", builder, ""),
372+
policylabelunarchive.NewCommand("unarchive", builder, ""),
373+
},
374+
},
375+
{
376+
Use: "settings",
377+
Short: "Manage a policy's settings",
378+
SubCommands: []*appcmd.Command{
379+
policysettingsupdate.NewCommand("update", builder),
380+
},
381+
},
382+
policycreate.NewCommand("create", builder),
383+
policyinfo.NewCommand("info", builder),
384+
policydelete.NewCommand("delete", builder),
385+
},
386+
},
338387
},
339388
},
340389
{
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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 policycommitaddlabel
16+
17+
import (
18+
"context"
19+
"fmt"
20+
21+
policyv1beta1 "buf.build/gen/go/bufbuild/registry/protocolbuffers/go/buf/registry/policy/v1beta1"
22+
"buf.build/go/app/appcmd"
23+
"buf.build/go/app/appext"
24+
"buf.build/go/standard/xslices"
25+
"connectrpc.com/connect"
26+
"github.com/bufbuild/buf/private/buf/bufcli"
27+
"github.com/bufbuild/buf/private/buf/bufprint"
28+
"github.com/bufbuild/buf/private/bufpkg/bufparse"
29+
"github.com/bufbuild/buf/private/bufpkg/bufregistryapi/bufregistryapipolicy"
30+
"github.com/bufbuild/buf/private/pkg/uuidutil"
31+
"github.com/spf13/pflag"
32+
)
33+
34+
const (
35+
formatFlagName = "format"
36+
labelsFlagName = "label"
37+
)
38+
39+
// NewCommand returns a new Command.
40+
func NewCommand(
41+
name string,
42+
builder appext.SubCommandBuilder,
43+
deprecated string,
44+
) *appcmd.Command {
45+
flags := newFlags()
46+
return &appcmd.Command{
47+
Use: name + " <remote/owner/policy:commit> --label <label>",
48+
Short: "Add labels to a commit",
49+
Args: appcmd.ExactArgs(1),
50+
Deprecated: deprecated,
51+
Run: builder.NewRunFunc(
52+
func(ctx context.Context, container appext.Container) error {
53+
return run(ctx, container, flags)
54+
},
55+
),
56+
BindFlags: flags.Bind,
57+
}
58+
}
59+
60+
type flags struct {
61+
Format string
62+
Labels []string
63+
}
64+
65+
func newFlags() *flags {
66+
return &flags{}
67+
}
68+
69+
func (f *flags) Bind(flagSet *pflag.FlagSet) {
70+
flagSet.StringVar(
71+
&f.Format,
72+
formatFlagName,
73+
bufprint.FormatText.String(),
74+
fmt.Sprintf(`The output format to use. Must be one of %s`, bufprint.AllFormatsString),
75+
)
76+
flagSet.StringSliceVar(
77+
&f.Labels,
78+
labelsFlagName,
79+
nil,
80+
"The labels to add to the commit. Must have at least one",
81+
)
82+
}
83+
84+
func run(
85+
ctx context.Context,
86+
container appext.Container,
87+
flags *flags,
88+
) error {
89+
policyRef, err := bufparse.ParseRef(container.Arg(0))
90+
if err != nil {
91+
return appcmd.WrapInvalidArgumentError(err)
92+
}
93+
if policyRef.Ref() == "" {
94+
return appcmd.NewInvalidArgumentError("commit is required")
95+
}
96+
commitID := policyRef.Ref()
97+
if _, err := uuidutil.FromDashless(commitID); err != nil {
98+
return appcmd.NewInvalidArgumentErrorf("invalid commit: %w", err)
99+
}
100+
labels := flags.Labels
101+
if len(labels) == 0 {
102+
return appcmd.NewInvalidArgumentError("must create at least one label")
103+
}
104+
format, err := bufprint.ParseFormat(flags.Format)
105+
if err != nil {
106+
return appcmd.WrapInvalidArgumentError(err)
107+
}
108+
clientConfig, err := bufcli.NewConnectClientConfig(container)
109+
if err != nil {
110+
return err
111+
}
112+
policyClientProvider := bufregistryapipolicy.NewClientProvider(clientConfig)
113+
labelServiceClient := policyClientProvider.V1Beta1LabelServiceClient(policyRef.FullName().Registry())
114+
requestValues := xslices.Map(labels, func(label string) *policyv1beta1.CreateOrUpdateLabelsRequest_Value {
115+
return &policyv1beta1.CreateOrUpdateLabelsRequest_Value{
116+
LabelRef: &policyv1beta1.LabelRef{
117+
Value: &policyv1beta1.LabelRef_Name_{
118+
Name: &policyv1beta1.LabelRef_Name{
119+
Owner: policyRef.FullName().Owner(),
120+
Policy: policyRef.FullName().Name(),
121+
Label: label,
122+
},
123+
},
124+
},
125+
CommitId: commitID,
126+
}
127+
})
128+
resp, err := labelServiceClient.CreateOrUpdateLabels(
129+
ctx,
130+
connect.NewRequest(
131+
&policyv1beta1.CreateOrUpdateLabelsRequest{
132+
Values: requestValues,
133+
},
134+
),
135+
)
136+
if err != nil {
137+
// Not explicitly handling error with connect.CodeNotFound as
138+
// it can be Policy or Commit not found error. May be caused by
139+
// a misformatted ID.
140+
return err
141+
}
142+
return bufprint.PrintNames(
143+
container.Stdout(),
144+
format,
145+
xslices.Map(resp.Msg.Labels, func(label *policyv1beta1.Label) bufprint.Entity {
146+
return bufprint.NewLabelEntity(label, policyRef.FullName())
147+
})...,
148+
)
149+
}

private/buf/cmd/buf/command/registry/policy/policycommit/policycommitaddlabel/usage.gen.go

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)