-
Notifications
You must be signed in to change notification settings - Fork 21
(feat): markers: add support for parsing DV tags #152
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
base: main
Are you sure you want to change the base?
(feat): markers: add support for parsing DV tags #152
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: everettraven The full list of commands accepted by this bot can be found here.
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
4dc9e20 to
375334c
Compare
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.
Do you think it would be possible to chain non-dv tags with DV tags? E.g. if we wanted to put a kubebuilder tag behind a k8s:ifEnabled? Would this parsing support that?
| } | ||
|
|
||
| func extractGenDeclMarkers(typ *ast.GenDecl, results *markers) { | ||
| func extractGenDeclMarkers(typ *ast.GenDecl, results *markers) error { |
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.
This change is breaking linting in other places, PTAL at the linting
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.
Ack, will do.
| if marker := extractMarker(comment); marker.Identifier != "" { | ||
| marker, err := extractMarker(comment) | ||
| if err != nil { | ||
| return err |
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.
wrap the error with context please
| if marker := extractMarker(comment); marker.Identifier != "" { | ||
| marker, err := extractMarker(comment) | ||
| if err != nil { | ||
| return err |
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.
Wrap with context please
| switch tag.ValueType { | ||
| case codetags.ValueTypeString, codetags.ValueTypeInt, codetags.ValueTypeBool, codetags.ValueTypeRaw: | ||
| // all resolvable to an exact string value | ||
| out.Expressions["payload"] = tag.Value |
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.
Wouldn't this normally be "" in our existing marker semantics?
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.
Yes, but DV tags are a bit different in the sense that they potentially have named and unnamed arguments and a "payload".
Thinking about this some more, I'm actually thinking we may want to update how we parse existing kubebuilder markers to either change what we considered "expressions" to be "arguments".
I could see it being worth it to add typing to the markers to signal which marker this was parsed as and a helper utility for reconstruction.
| case codetags.ValueTypeNone: | ||
| // nothing | ||
| case codetags.ValueTypeTag: | ||
| // TODO: Better position evaluation |
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.
What's wrong with the existing version?
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.
Nothing inherently wrong, but any future logic that may recommend changes to a nested marker may need to take into account that the changes would be on the whole line and not just the subsection where the marker is.
My "TODO" here was with the idea that we might be able to improve a bit here, but thinking about it some more, I'm not quite sure the juice is worth the squeeze - at least not at this moment.
| expect: func(m Marker) error { | ||
| expectedID := "required" | ||
| if m.Identifier != expectedID { | ||
| return fmt.Errorf("marker identifier %q does not match expected %q", m.Identifier, expectedID) | ||
| } | ||
| 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.
Might be worth writing a helper for this that takes the expected ID as an argument and using that to return the function rather than repeating this many times
| return fmt.Errorf("identifier %q did not match expected identifier %q", m.Identifier, "k8s:unionMember") | ||
| } | ||
|
|
||
| union, ok := m.Expressions["union"] |
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.
I can't help but feel we are now mixing two different kinds of args (those in payload vs those in the args/parentheses) and that these should be expressed differently, else we can't reliably reconstruct right?
| shouldBeMarker: true, | ||
| expectedID: "k8s:someThing(one: \"a\", two: \"b\")", | ||
| name: "declarative validation marker with multiple named arguments", | ||
| comment: &ast.Comment{Text: "// +k8s:someThing(one: \"a\", two: \"b\")=+k8s:required"}, |
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 payload isn't checked here?
Good question. I haven't tested whether something like I'm pretty certain something like My initial stance is that we don't support the mixing of the two. We should actually add a new linter that flags the cases that would end up passing parsing. I'm not sure carrying the additional complexity of supporting that scenario on either the linter or generative tooling side is worth it there. |
375334c to
952a3de
Compare
| if err != nil { | ||
| 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.
Instead of returning an error up the chain, I decided staying consistent with the behavior that exists for non-matching markers (no error, just return an empty marker object) is the better path here.
I think malformed dv markers can be added to the set of "typo" detection we do in #23 (either during initial implementation or later).
| } | ||
|
|
||
| for _, arg := range tag.Args { | ||
| out.Arguments[arg.Name] = arg.Value |
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.
Positional arguments, of which only one is allowed in a DV tag, the argument name will be "" which aligns with our UnnamedArgument constant.
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
952a3de to
3e58f96
Compare
Kube-api-linter will eventually need to support parsing declarative validation tags for core k/k integration and potentially for controller-tools changes that support DV tag usage on CRDs.
This PR imports the DV tag parsing and adds a special conditional branch to the marker extraction logic to handle DV tags specifically.
The scope of this PR is limited to enabling the parsing of current and future DV tags and does not include functional changes to how individual linters interact with the parsed markers.
For simple DV tags it should be straightforward as to how linter rules handle them.
For the future DV tags where there is conditional behavior it will not be as straightforward. Because these future DV tags are still in the alpha stage we are deferring any special handling considerations to the time in which we need to implement support for them.