Documentation
¶
Overview ¶
Package check implements the SDK for custom lint and breaking change plugins.
Index ¶
- func CompareAnnotations(one Annotation, two Annotation) int
- func CompareCategories(one Category, two Category) int
- func CompareRules(one Rule, two Rule) int
- func Main(spec *Spec, options ...MainOption)
- func NewCheckServiceHandler(spec *Spec, options ...CheckServiceHandlerOption) (v1pluginrpc.CheckServiceHandler, error)
- func NewServer(spec *Spec, options ...ServerOption) (pluginrpc.Server, error)
- func ValidateSpec(spec *Spec) error
- type AddAnnotationOption
- func WithAgainstDescriptor(againstDescriptor protoreflect.Descriptor) AddAnnotationOption
- func WithAgainstFileName(againstFileName string) AddAnnotationOption
- func WithAgainstFileNameAndSourcePath(againstFileName string, againstSourcePath protoreflect.SourcePath) AddAnnotationOption
- func WithDescriptor(descriptor protoreflect.Descriptor) AddAnnotationOption
- func WithFileName(fileName string) AddAnnotationOption
- func WithFileNameAndSourcePath(fileName string, sourcePath protoreflect.SourcePath) AddAnnotationOption
- func WithMessage(message string) AddAnnotationOption
- func WithMessagef(format string, args ...any) AddAnnotationOption
- type Annotation
- type Category
- type CategorySpec
- type CheckCallOption
- type CheckServiceHandlerOption
- type Client
- type ClientForSpecOption
- type ClientOption
- type ListCategoriesCallOption
- type ListRulesCallOption
- type MainOption
- type Request
- type RequestOption
- type Response
- type ResponseWriter
- type Rule
- type RuleHandler
- type RuleHandlerFunc
- type RuleSpec
- type RuleType
- type ServerOption
- type Spec
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CompareAnnotations ¶
func CompareAnnotations(one Annotation, two Annotation) int
CompareAnnotations returns -1 if one < two, 1 if one > two, 0 otherwise.
func CompareCategories ¶
CompareCategories returns -1 if one < two, 1 if one > two, 0 otherwise.
func CompareRules ¶
CompareRules returns -1 if one < two, 1 if one > two, 0 otherwise.
func Main ¶
func Main(spec *Spec, options ...MainOption)
Main is the main entrypoint for a plugin that implements the given Spec.
A plugin just needs to provide a Spec, and then call this function within main.
func main() { check.Main( &check.Spec { Rules: []*check.RuleSpec{ { ID: "TIMESTAMP_SUFFIX", Default: true, Purpose: "Checks that all google.protobuf.Timestamps end in _time.", Type: check.RuleTypeLint, Handler: check.RuleHandlerFunc(handleTimestampSuffix), }, }, }, ) }
func NewCheckServiceHandler ¶
func NewCheckServiceHandler(spec *Spec, options ...CheckServiceHandlerOption) (v1pluginrpc.CheckServiceHandler, error)
NewCheckServiceHandler returns a new v1pluginrpc.CheckServiceHandler for the given Spec.
The Spec will be validated.
func NewServer ¶ added in v0.4.0
func NewServer(spec *Spec, options ...ServerOption) (pluginrpc.Server, error)
NewServer is a convenience function that creates a new pluginrpc.Server for the given Spec.
This registers:
- The Check RPC on the command "check". - The ListRules RPC on the command "list-rules". - The ListCategories RPC on the command "list-categories". - The GetPluginInfo RPC on the command "info" (if spec.Info is present).
func ValidateSpec ¶
ValidateSpec validates all values on a Spec.
This is exposed publicly so it can be run as part of plugin tests. This will verify that your Spec will result in a valid plugin.
Types ¶
type AddAnnotationOption ¶
type AddAnnotationOption func(*addAnnotationOptions)
AddAnnotationOption is an option with adding an Annotation to a ResponseWriter.
func WithAgainstDescriptor ¶
func WithAgainstDescriptor(againstDescriptor protoreflect.Descriptor) AddAnnotationOption
WithAgainstDescriptor will set the AgainstLocation on the Annotation by extracting file and source path information from the descriptor itself.
It is not valid to use WithAgainstDescriptor if also using either WithAgainstFileName or WithAgainstSourcePath.
func WithAgainstFileName ¶
func WithAgainstFileName(againstFileName string) AddAnnotationOption
WithAgainstFileName will set the FileName on the Annotation's AgainstLocation directly.
Typically, most users will use WithAgainstDescriptor to accomplish this task.
This will not set any line/column information. To do so, use WithAgainstFileNameAndSourcePath.
It is not valid to use WithAgainstDescriptor if also using either WithAgainstFileName or WithAgainstFileNameAndSourcePath.
func WithAgainstFileNameAndSourcePath ¶
func WithAgainstFileNameAndSourcePath(againstFileName string, againstSourcePath protoreflect.SourcePath) AddAnnotationOption
WithAgainstFileNameAndSourcePath will set the Filename and SourcePath on the Annotation's AgainstLocation directly.
Typically, most users will use WithAgainstDescriptor to accomplish this task.
It is not valid to use WithAgainstDescriptor if also using either WithAgainstFileName or WithAgainstFileNameAndSourcePath.
func WithDescriptor ¶
func WithDescriptor(descriptor protoreflect.Descriptor) AddAnnotationOption
WithDescriptor will set the Location on the Annotation by extracting file and source path information from the descriptor itself.
It is not valid to use WithDescriptor if also using either WithFileName or WithSourcePath.
func WithFileName ¶
func WithFileName(fileName string) AddAnnotationOption
WithFileName will set the FileName on the Annotation's Location directly.
Typically, most users will use WithDescriptor to accomplish this task.
This will not set any line/column information. To do so, use WithFileNameAndSourcePath.
It is not valid to use WithDescriptor if also using either WithFileName or WithFileNameAndSourcePath.
func WithFileNameAndSourcePath ¶
func WithFileNameAndSourcePath(fileName string, sourcePath protoreflect.SourcePath) AddAnnotationOption
WithFileNameAndSourcePath will set the SourcePath on the Annotation's Location directly.
Typically, most users will use WithDescriptor to accomplish this task.
It is not valid to use WithDescriptor if also using either WithFileName or WithFileNameAndSourcePath.
func WithMessage ¶
func WithMessage(message string) AddAnnotationOption
WithMessage sets the message on the Annotation.
If there are multiple calls to WithMessage or WithMessagef, the last one wins.
func WithMessagef ¶
func WithMessagef(format string, args ...any) AddAnnotationOption
WithMessagef sets the message on the Annotation.
If there are multiple calls to WithMessage or WithMessagef, the last one wins.
type Annotation ¶
type Annotation interface { // RuleID is the ID of the Rule that failed. // // This will always be present. RuleID() string // Message is a user-readable message describing the failure. Message() string // FileLocation is the location of the failure. FileLocation() descriptor.FileLocation // AgainstFileLocation is the FileLocation of the failure in the against FileDescriptors. // // Will only potentially be produced for breaking change rules. AgainstFileLocation() descriptor.FileLocation // contains filtered or unexported methods }
Annotation represents a rule Failure.
An annotation always contains the ID of the Rule that failed. It also optionally contains a user-readable message, a location of the failure, and a location of the failure in the against FileDescriptors.
Annotations are created on the server-side via ResponseWriters, and returned from Clients on Responses.
type Category ¶
type Category interface { // ID is the ID of the Category. // // Always present. // // This uniquely identifies the Category. ID() string // A user-displayable purpose of the category. // // Always present. Purpose() string // Deprecated returns whether or not this Category is deprecated. // // If the Category is deprecated, it may be replaced by zero or more Categories. These will // be denoted by ReplacementIDs. Deprecated() bool // ReplacementIDs returns the IDs of the Categories that replace this Category, if this Category is deprecated. // // This means that the combination of the Categories specified by ReplacementIDs replace this Category entirely, // and this Category is considered equivalent to the AND of the categories specified by ReplacementIDs. // // This will only be non-empty if Deprecated is true. // // It is not valid for a deprecated Category to specfiy another deprecated Category as a replacement. ReplacementIDs() []string // contains filtered or unexported methods }
Category is rule category.
Categories have unique IDs. On the server-side (i.e. the plugin), Categories are created by CategorySpecs. Clients can list all available plugin Categories by calling ListCategories.
type CategorySpec ¶
type CategorySpec struct { // Required. ID string // Required. Purpose string Deprecated bool ReplacementIDs []string }
CategorySpec is the spec for a Category.
It is used to construct a Category on the server-side (i.e. within the plugin). It specifies the ID, purpose, and a CategoryHandler to actually run the Category logic.
Generally, these are provided to Main. This library will handle Check and ListCategories calls based on the provided CategorySpecs.
type CheckCallOption ¶
type CheckCallOption func(*checkCallOptions)
CheckCallOption is an option for a Client.Check call.
type CheckServiceHandlerOption ¶
type CheckServiceHandlerOption func(*checkServiceHandlerOptions)
CheckServiceHandlerOption is an option for CheckServiceHandler.
func CheckServiceHandlerWithParallelism ¶
func CheckServiceHandlerWithParallelism(parallelism int) CheckServiceHandlerOption
CheckServiceHandlerWithParallelism returns a new CheckServiceHandlerOption that sets the parallelism by which Rules will be run.
If this is set to a value >= 1, this many concurrent Rules can be run at the same time. A value of 0 indicates the default behavior, which is to use runtime.GOMAXPROCS(0).
A value if < 0 has no effect.
type Client ¶
type Client interface { info.Client // Check invokes a check using the plugin.. Check(ctx context.Context, request Request, options ...CheckCallOption) (Response, error) // ListRules lists all available Rules from the plugin. // // The Rules will be sorted by Rule ID. // Returns error if duplicate Rule IDs were detected from the underlying source. ListRules(ctx context.Context, options ...ListRulesCallOption) ([]Rule, error) // ListCategories lists all available Categories from the plugin. // // The Categories will be sorted by Category ID. // Returns error if duplicate Category IDs were detected from the underlying source. ListCategories(ctx context.Context, options ...ListCategoriesCallOption) ([]Category, error) // contains filtered or unexported methods }
Client is a client for a custom lint or breaking change plugin.
All calls with pluginrpc.Error with CodeUnimplemented if any procedure is not implemented.
func NewClient ¶
func NewClient(pluginrpcClient pluginrpc.Client, options ...ClientOption) Client
NewClient returns a new Client for the given pluginrpc.Client.
func NewClientForSpec ¶
func NewClientForSpec(spec *Spec, options ...ClientForSpecOption) (Client, error)
NewClientForSpec return a new Client that directly uses the given Spec.
This should primarily be used for testing.
type ClientForSpecOption ¶
type ClientForSpecOption interface {
// contains filtered or unexported methods
}
ClientForSpecOption is an option for a new Client constructed with NewClientForSpec.
type ClientOption ¶
type ClientOption interface { ClientForSpecOption // contains filtered or unexported methods }
ClientOption is an option for a new Client.
func ClientWithCaching ¶ added in v0.4.0
func ClientWithCaching() ClientOption
ClientWithCaching returns a new ClientOption that will result caching for items expected to be static:
- The Rules from ListRules. - The Categories from ListCategories. - PluginInfo from GetPluginInfo.
The default is to not cache.
type ListCategoriesCallOption ¶
type ListCategoriesCallOption func(*listCategoriesCallOptions)
ListCategoriesCallOption is an option for a Client.ListCategories call.
type ListRulesCallOption ¶
type ListRulesCallOption func(*listRulesCallOptions)
ListRulesCallOption is an option for a Client.ListRules call.
type MainOption ¶
type MainOption func(*mainOptions)
MainOption is an option for Main.
func MainWithParallelism ¶
func MainWithParallelism(parallelism int) MainOption
MainWithParallelism returns a new MainOption that sets the parallelism by which Rules will be run.
If this is set to a value >= 1, this many concurrent Rules can be run at the same time. A value of 0 indicates the default behavior, which is to use runtime.GOMAXPROCS(0).
A value if < 0 has no effect.
type Request ¶
type Request interface { // FileDescriptors contains the FileDescriptors to check. // // Will never be nil or empty. // // FileDescriptors are guaranteed to be unique with respect to their name. FileDescriptors() []descriptor.FileDescriptor // AgainstFileDescriptors contains the FileDescriptors to check against, in the // case of breaking change plugins. // // May be empty, including in the case where we did actually specify against // FileDescriptors. // // FileDescriptors are guaranteed to be unique with respect to their name. AgainstFileDescriptors() []descriptor.FileDescriptor // Options contains any options passed to the plugin. // // Will never be nil, but may have no values. Options() option.Options // RuleIDs returns the specific IDs the of Rules to use. // // If empty, all default Rules will be used. // The returned RuleIDs will be sorted. // // This may return more than 250 IDs; the underlying Client implemention is required to do // any necessary chunking. // // RuleHandlers can safely ignore this - the handling of RuleIDs will have already // been performed prior to the Request reaching the RuleHandler. RuleIDs() []string // contains filtered or unexported methods }
Request is a request to a plugin to run checks.
func NewRequest ¶
func NewRequest( fileDescriptors []descriptor.FileDescriptor, options ...RequestOption, ) (Request, error)
NewRequest returns a new Request for the given FileDescriptors.
FileDescriptors are always required. To set against FileDescriptors or options, use WithAgainstFileDescriptors and WithOption.
func RequestForProtoRequest ¶
func RequestForProtoRequest(protoRequest *checkv1.CheckRequest) (Request, error)
RequestForProtoRequest returns a new Request for the given checkv1.Request.
type RequestOption ¶
type RequestOption func(*requestOptions)
RequestOption is an option for a new Request.
func WithAgainstFileDescriptors ¶ added in v0.3.0
func WithAgainstFileDescriptors(againstFileDescriptors []descriptor.FileDescriptor) RequestOption
WithAgainstFileDescriptors adds the given against FileDescriptors to the Request.
func WithOptions ¶
func WithOptions(options option.Options) RequestOption
WithOption adds the given Options to the Request.
func WithRuleIDs ¶
func WithRuleIDs(ruleIDs ...string) RequestOption
WithRuleIDs specifies that the given rule IDs should be used on the Request.
Multiple calls to WithRuleIDs will result in the new rule IDs being appended. If duplicate rule IDs are specified, this will result in an error.
type Response ¶
type Response interface { // Annotations returns all of the Annotations. // // The returned annotations will be sorted. Annotations() []Annotation // contains filtered or unexported methods }
Response is a response from a plugin for a check call.
type ResponseWriter ¶
type ResponseWriter interface { // AddAnnotation adds an Annotation with the rule ID that is tied to this ResponseWriter. // // Fields of the Annotation are controlled with AddAnnotationOptions, of which there are several: // // - WithMessage/WithMessagef: Add a message to the Annotation. // - WithDescriptor/WithAgainstDescriptor: Use the protoreflect.Descriptor to determine Location information. // - WithFileName/WithAgainstFileName: Use the given file name on the Location. // - WithFileNameAndSourcePath/WithAgainstFileNameAndSourcePath: Use the given explicit file name and source path on the Location. // // There are some rules to note when using AddAnnotationOptions: // // - Multiple calls of WithMessage/WithMessagef will overwrite previous calls. // - You must either use WithDescriptor, or use WithFileName/WithSourcePath, but you cannot // use these together. Location information is determined either from the Descriptor, or // from explicit setting via WithFileName/WithFileNameAndSourcePath. Same applies to the Against equivalents. // // Don't worry, these rules are verified when building a Response. // // Most users will use WithDescriptor/WithAgainstDescriptor as opposed to their lower-level variants. AddAnnotation(options ...AddAnnotationOption) // contains filtered or unexported methods }
ResponseWriter is used by plugin implmentations to add Annotations to responses.
A ResponseWriter is tied to a specific rule, and is passed to a RuleHandler. The ID of the Rule will be automatically populated for any added Annotations.
type Rule ¶
type Rule interface { // ID is the ID of the Rule. // // Always present. // // This uniquely identifies the Rule. ID() string // The categories that the Rule is a part of. // // Optional. // // Buf uses categories to include or exclude sets of rules via configuration. Categories() []Category // Whether or not the Rule is a default Rule. // // If a Rule is a default Rule, it will be called if a Request specifies no specific Rule IDs. // // A deprecated rule cannot be a default rule. Default() bool // A user-displayable purpose of the rule. // // Always present. // // This should be a proper sentence that starts with a capital letter and ends in a period. Purpose() string // Type is the type of the Rule. Type() RuleType // Deprecated returns whether or not this Rule is deprecated. // // If the Rule is deprecated, it may be replaced by 0 or more Rules. These will be denoted // by ReplacementIDs. Deprecated() bool // ReplacementIDs returns the IDs of the Rules that replace this Rule, if this Rule is deprecated. // // This means that the combination of the Rules specified by ReplacementIDs replace this Rule entirely, // and this Rule is considered equivalent to the AND of the rules specified by ReplacementIDs. // // This will only be non-empty if Deprecated is true. // // It is not valid for a deprecated Rule to specfiy another deprecated Rule as a replacement. ReplacementIDs() []string // contains filtered or unexported methods }
Rule is a single lint or breaking change rule.
Rules have unique IDs. On the server-side (i.e. the plugin), Rules are created by RuleSpecs. Clients can list all available plugin Rules by calling ListRules.
type RuleHandler ¶
type RuleHandler interface {
Handle(ctx context.Context, responseWriter ResponseWriter, request Request) error
}
RuleHandler implements the check logic for a single Rule.
A RuleHandler takes in a Request, and writes Annotations to the ResponseWriter.
type RuleHandlerFunc ¶
type RuleHandlerFunc func(context.Context, ResponseWriter, Request) error
RuleHandlerFunc is a function that implements RuleHandler.
func (RuleHandlerFunc) Handle ¶
func (r RuleHandlerFunc) Handle(ctx context.Context, responseWriter ResponseWriter, request Request) error
Handle implements RuleHandler.
type RuleSpec ¶
type RuleSpec struct { // Required. ID string CategoryIDs []string Default bool // Required. Purpose string // Required. Type RuleType Deprecated bool ReplacementIDs []string // Required. Handler RuleHandler }
RuleSpec is the spec for a Rule.
It is used to construct a Rule on the server-side (i.e. within the plugin). It specifies the ID, categories, purpose, type, and a RuleHandler to actually run the Rule logic.
Generally, these are provided to Main. This library will handle Check and ListRules calls based on the provided RuleSpecs.
type ServerOption ¶ added in v0.4.0
type ServerOption func(*serverOptions)
ServerOption is an option for Server.
func ServerWithParallelism ¶ added in v0.4.0
func ServerWithParallelism(parallelism int) ServerOption
ServerWithParallelism returns a new ServerOption that sets the parallelism by which Rules will be run.
If this is set to a value >= 1, this many concurrent Rules can be run at the same time. A value of 0 indicates the default behavior, which is to use runtime.GOMAXPROCS(0).
A value if < 0 has no effect.
type Spec ¶
type Spec struct { // Required. // // All RuleSpecs must have Category IDs that match a CategorySpec within Categories. // // No IDs can overlap with Category IDs in Categories. Rules []*RuleSpec // Required if any RuleSpec specifies a category. // // All CategorySpecs must have an ID that matches at least one Category ID on a // RuleSpec within Rules. // // No IDs can overlap with Rule IDs in Rules. Categories []*CategorySpec // Info contains information about a plugin. // // Optional. // // If not set, the resulting server will not implement the PluginInfoService. Info *info.Spec // Before is a function that will be executed before any RuleHandlers are // invoked that returns a new Context and Request. This new Context and // Request will be passed to the RuleHandlers. This allows for any // pre-processing that needs to occur. Before func(ctx context.Context, request Request) (context.Context, Request, error) }
Spec is the spec for a plugin.
It is used to construct a plugin on the server-side (i.e. within the plugin).
Generally, this is provided to Main. This library will handle Check and ListRules calls based on the provided RuleSpecs.
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
Package checktest provides testing helpers when writing lint and breaking change plugins.
|
Package checktest provides testing helpers when writing lint and breaking change plugins. |
Package checkutil implements helpers for the check package.
|
Package checkutil implements helpers for the check package. |
internal
|
|
example/cmd/buf-plugin-field-lower-snake-case
Package main implements a simple plugin that checks that all field names are lower_snake_case.
|
Package main implements a simple plugin that checks that all field names are lower_snake_case. |
example/cmd/buf-plugin-field-option-safe-for-ml
Package main implements a plugin that implements two Rules:
|
Package main implements a plugin that implements two Rules: |
example/cmd/buf-plugin-syntax-specified
Package main implements a simple plugin that checks that syntax is specified in every file.
|
Package main implements a simple plugin that checks that syntax is specified in every file. |
example/cmd/buf-plugin-timestamp-suffix
Package main implements a simple plugin that checks that all google.protobuf.Timestamp fields end in a specific suffix.
|
Package main implements a simple plugin that checks that all google.protobuf.Timestamp fields end in a specific suffix. |