-
Notifications
You must be signed in to change notification settings - Fork 346
Add --against-registry flag for buf breaking
#3696
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
d9cbd08
72fe887
f5f522d
05d5dd6
e6befb7
0fb4b36
182f01f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,6 +30,7 @@ import ( | |
| "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/bufbuild/buf/private/pkg/wasm" | ||
| "github.com/spf13/pflag" | ||
| ) | ||
|
|
@@ -42,6 +43,7 @@ const ( | |
| configFlagName = "config" | ||
| againstFlagName = "against" | ||
| againstConfigFlagName = "against-config" | ||
| againstRegistryFlagName = "against-registry" | ||
| excludePathsFlagName = "exclude-path" | ||
| disableSymlinksFlagName = "disable-symlinks" | ||
| ) | ||
|
|
@@ -77,6 +79,7 @@ type flags struct { | |
| Config string | ||
| Against string | ||
| AgainstConfig string | ||
| AgainstRegistry bool | ||
| ExcludePaths []string | ||
| DisableSymlinks bool | ||
| // special | ||
|
|
@@ -129,7 +132,8 @@ Overrides --%s`, | |
| againstFlagName, | ||
| "", | ||
| fmt.Sprintf( | ||
| `Required. The source, module, or image to check against. Must be one of format %s`, | ||
| `Required, except if --%s is set. The source, module, or image to check against. Must be one of format %s`, | ||
| againstRegistryFlagName, | ||
| buffetch.AllFormatsString, | ||
| ), | ||
| ) | ||
|
|
@@ -139,14 +143,24 @@ Overrides --%s`, | |
| "", | ||
| `The buf.yaml file or data to use to configure the against source, module, or image`, | ||
| ) | ||
| flagSet.BoolVar( | ||
| &f.AgainstRegistry, | ||
| againstRegistryFlagName, | ||
| false, | ||
| fmt.Sprintf( | ||
| `Run breaking checks against the latest commit on the default branch in the registry. All modules in the input must have a name configured, otherwise this will fail. | ||
| If a remote module is not found with the configured name, then this will fail. This cannot be set with --%s.`, | ||
| againstFlagName, | ||
| ), | ||
| ) | ||
| } | ||
|
|
||
| func run( | ||
| ctx context.Context, | ||
| container appext.Container, | ||
| flags *flags, | ||
| ) (retErr error) { | ||
| if err := bufcli.ValidateRequiredFlag(againstFlagName, flags.Against); err != nil { | ||
| if err := validateFlags(flags); err != nil { | ||
| return err | ||
| } | ||
| input, err := bufcli.GetInputValue(container, flags.InputHashtag, ".") | ||
|
|
@@ -194,19 +208,64 @@ func run( | |
| return err | ||
| } | ||
| } | ||
| // Do not exclude imports here. bufcheck's Client requires all imports. | ||
| // Use bufcheck's BreakingWithExcludeImports. | ||
| againstImageWithConfigs, _, err := controller.GetTargetImageWithConfigsAndCheckClient( | ||
| ctx, | ||
| flags.Against, | ||
| wasm.UnimplementedRuntime, | ||
| bufctl.WithTargetPaths(externalPaths, flags.ExcludePaths), | ||
| bufctl.WithConfigOverride(flags.AgainstConfig), | ||
| ) | ||
| if err != nil { | ||
| return err | ||
| var againstImages []bufimage.Image | ||
| if flags.Against != "" { | ||
| // Do not exclude imports here. bufcheck's Client requires all imports. | ||
| // Use bufcheck's BreakingWithExcludeImports. | ||
| againstImagesWithConfigs, _, err := controller.GetTargetImageWithConfigsAndCheckClient( | ||
| ctx, | ||
| flags.Against, | ||
| wasm.UnimplementedRuntime, | ||
| bufctl.WithTargetPaths(externalPaths, flags.ExcludePaths), | ||
| bufctl.WithConfigOverride(flags.AgainstConfig), | ||
| ) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| // We do not require the check configs from the against target once built, so they can | ||
| // be dropped here. | ||
| againstImages, err = slicesext.MapError( | ||
| againstImagesWithConfigs, | ||
| func(imageWithConfig bufctl.ImageWithConfig) (bufimage.Image, error) { | ||
| againstImage, ok := imageWithConfig.(bufimage.Image) | ||
| if !ok { | ||
| return nil, syserror.New("imageWithConfig could not be converted to Image") | ||
| } | ||
| return againstImage, nil | ||
| }, | ||
| ) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| } | ||
| if len(imageWithConfigs) != len(againstImageWithConfigs) { | ||
| if flags.AgainstRegistry { | ||
| for _, imageWithConfig := range imageWithConfigs { | ||
| if imageWithConfig.ModuleFullName() == nil { | ||
| if imageWithConfig.ModuleOpaqueID() == "" { | ||
| // This can occur in the case of a [buffetch.MessageRef], where we resolve the message | ||
| // ref directly from the bucket without building the [bufmodule.Module]. In that case, | ||
| // we are unnable to use --against-registry. | ||
| return fmt.Errorf("cannot use --%s with unnamed module", againstRegistryFlagName) | ||
| } | ||
| return fmt.Errorf( | ||
| "cannot use --%s with unnamed module, %s", | ||
| againstRegistryFlagName, | ||
| imageWithConfig.ModuleOpaqueID(), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to check for empty opaque ID here?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re: the comment above, the
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adjusted this error for the |
||
| ) | ||
| } | ||
| againstImage, err := controller.GetImage( | ||
| ctx, | ||
| imageWithConfig.ModuleFullName().String(), | ||
| bufctl.WithTargetPaths(externalPaths, flags.ExcludePaths), | ||
| bufctl.WithConfigOverride(flags.AgainstConfig), | ||
| ) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| againstImages = append(againstImages, againstImage) | ||
| } | ||
| } | ||
| if len(imageWithConfigs) != len(againstImages) { | ||
| // If workspaces are being used as input, the number | ||
| // of images MUST match. Otherwise the results will | ||
| // be meaningless and yield false positives. | ||
|
|
@@ -216,7 +275,7 @@ func run( | |
| return fmt.Errorf( | ||
| "input contained %d images, whereas against contained %d images", | ||
| len(imageWithConfigs), | ||
| len(againstImageWithConfigs), | ||
| len(againstImages), | ||
| ) | ||
| } | ||
| // We add all check configs (both lint and breaking) as related configs to check if plugins | ||
|
|
@@ -240,7 +299,7 @@ func run( | |
| ctx, | ||
| imageWithConfig.BreakingConfig(), | ||
| imageWithConfig, | ||
| againstImageWithConfigs[i], | ||
| againstImages[i], | ||
| breakingOptions..., | ||
| ); err != nil { | ||
| var fileAnnotationSet bufanalysis.FileAnnotationSet | ||
|
|
@@ -274,3 +333,13 @@ func getExternalPathsForImages[I bufimage.Image, S ~[]I](images S) ([]string, er | |
| } | ||
| return slicesext.MapKeysToSlice(externalPaths), nil | ||
| } | ||
|
|
||
| func validateFlags(flags *flags) error { | ||
| if flags.Against == "" && !flags.AgainstRegistry { | ||
| return fmt.Errorf("Must set --%s or --%s", againstFlagName, againstRegistryFlagName) | ||
| } | ||
| if flags.Against != "" && flags.AgainstRegistry { | ||
| return fmt.Errorf("Cannot set both --%s and --%s", againstFlagName, againstRegistryFlagName) | ||
| } | ||
| return nil | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this could be
Module() bufmodule.Moduleand document that it may be nil? From the docs it seems like theModule.FullNamemight be empty (like in Module) not that it isn't a Module, as the opaque ID can be empty.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
OpaqueIDshould always be present:buf/private/bufpkg/bufmodule/module.go
Lines 42 to 60 in 37b5a2a
My reasoning for not carrying the entire
Modulearound is because theImageshould be a compiled version of theModule(and theModuleis otherwise lazily loaded) -- so it seems unnecessary... but maybe it's easier?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed outside of the PR: this is mostly for the case of
messageRef, where we resolve the message through the bucket without theModule, so there is noFullNameorOpaqueID. In those cases, we are not able to use--against-registryflag.