Skip to content

add statussubresource lint check #2

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

Merged

Conversation

everettraven
Copy link
Contributor

No description provided.

@JoelSpeed JoelSpeed mentioned this pull request Dec 6, 2024
27 tasks
@everettraven everettraven force-pushed the feature/statussubresource branch 2 times, most recently from e72c57e to ffb9a50 Compare December 6, 2024 14:48
@everettraven everettraven marked this pull request as ready for review December 6, 2024 14:48
@everettraven everettraven changed the title wip: statussubresource lint check add statussubresource lint check Dec 6, 2024
@everettraven everettraven force-pushed the feature/statussubresource branch from ffb9a50 to b70124f Compare December 6, 2024 15:01
TextEdits: []analysis.TextEdit{
// go one line above the struct and add the marker
{
Pos: sTyp.Pos() - token.Pos(len(name)) - token.Pos(2) - token.Pos(len("type")) - token.Pos(1),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raw inserts can be achieved by setting Pos to the sTyp.Pos(), and setting End to token.NoPos. I think this will achieve what you want here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll play around with this a bit more and see if I can get something cleaner. The key thing here is that I want the insert to be on the line above the struct

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditions linter I'm working on presently has an example of this same thing, and it's working as I'm expecting, that's how I knew to comment here. LMK if you can't get it working and I'll send you a snippet

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't get what you mentioned to work for my case. A snippet would be helpful, but setting:

{
    Pos: sTyp.Pos(),
    End: token.NoPos,
    ...
}

resulted in this:

// +kubebuilder:object:root:=true
type Baz 
// +kubebuilder:subresource:statusstruct {

I modified my original logic to be a bit more straightforward and explained it with a comment. With my existing logic I get the expected outcome of:

// +kubebuilder:object:root:=true
// +kubebuilder:subresource:status
type Baz struct {

@everettraven everettraven force-pushed the feature/statussubresource branch from fef728f to f8a2642 Compare December 6, 2024 16:54
Comment on lines 21 to 25
// KubebuilderRootMarker is the marker that indicates that a struct is the object root for code and CRD generation.
KubebuilderRootMarker = "kubebuilder:object:root:=true"

// KubebuilderStatusSubresourceMarker is the marker that indicates that the CRD generated for a struct should include the /status subresource.
KubebuilderStatusSubresourceMarker = "kubebuilder:subresource:status"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do these need to be exported?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not. Will unexport them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unexported them in the latest push

@everettraven everettraven force-pushed the feature/statussubresource branch from f8a2642 to 968363c Compare December 6, 2024 18:13
@everettraven everettraven force-pushed the feature/statussubresource branch 2 times, most recently from 7b718c2 to 72d777e Compare January 9, 2025 20:15
@@ -118,6 +118,23 @@ func run(pass *analysis.Pass) (interface{}, error) {
}

nodeFilter := []ast.Node{
// In order to get the godoc comments from a type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I was hacking on the maxLength implementation just before shutdown and came to a similar conclusion here, except, I concluded that I no longer needed TypeSpec in the filter, and got rid of extractTypeSpecMarkers.

My extractGenDeclMarkers looked like

func extractGenDeclMarkers(typ *ast.GenDecl, results *markers) {
	declMarkers := NewMarkerSet()

	if typ.Doc != nil {
		for _, comment := range typ.Doc.List {
			if marker := extractMarker(comment); marker.Value != "" {
				declMarkers.Insert(marker)
			}
		}
	}

	if len(typ.Specs) == 0 {
		return
	}

	tSpec, ok := typ.Specs[0].(*ast.TypeSpec)
	if !ok {
		return
	}

	results.insertTypeMarkers(tSpec, declMarkers)

	if sTyp, ok := tSpec.Type.(*ast.StructType); ok {
		results.insertStructMarkers(sTyp, declMarkers)
	}
}

So pretty similar conclusion, except I didn't iterate over a slice of specs. Is it actually possible for a GenDecl to represent more than one spec?

In my approach, I also didn't have mergeMarkerSets, that didn't seem necessary, any ideas why you needed it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding, based on the information from golang/go#27477, is that you could define types in this format:

// GenDecl picks up comments here
type (
    // TypeSpec picks up comments here
    Foo struct {...}
    
    // TypeSpec here too
    Bar struct {...}
)

Maybe we don't care about the fact that things could be defined that way, but I tried to write the implementation in this PR such that it respects that someone is able to do this in Go. I'm not sure it is a correct assumption, but I assumed that any comments picked up when parsing GenDecl comments should probably also be added to the types themselves - I can try to do more research on this assumption to see how controller-tools would handle a scenario like this.

The mergeMarkerSets was necessary since I kept the ast.TypeSpec node type in the list to facilitate the merging of any markers defined at the various scopes. The merging is essentially making something like:

// +kubebuilder:validation:MaxLength:=10
type (
    // +kubebuilder:validation:Pattern:='^[0-9A-Za-z]*$'
    Foo string

    // +kubebuilder:validation:Pattern:='^[a-z]*$'
    Bar string
)

Equivalent to:

// +kubebuilder:validation:MaxLength:=10 
// +kubebuilder:validation:Pattern:='^[0-9A-Za-z]*$'
type Foo string

// +kubebuilder:validation:MaxLength:=10
// +kubebuilder:validation:Pattern:='^[a-z]*$'
type Bar string

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure it is a correct assumption, but I assumed that any comments picked up when parsing GenDecl comments should probably also be added to the types themselves - I can try to do more research on this assumption to see how controller-tools would handle a scenario like this.

I think I would likely disagree with that assumption, in this case I would expect the comments on the TypeSpec to apply, not the GenDecl comments.

I have also never seen this pattern used.

If you think this is reasonable to support, I would make sure we have tests for this, and we need to agree on the merging. For now, personally I would lean towards not supporting this type of declaration until/unless someone uses it (this is an early stage project, we don't have to support everything right now). A good smoke test would be to check if you can see this used in k/api at all.

Comment on lines 139 to 141
if sTyp == nil {
return false
}

if sTyp.Fields == nil || sTyp.Fields.List == nil {
return false
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit, could combine these right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah I could.

Name string `json:"name"`
}

// Test that it works with 'root=true' as well
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you have the test I wanted to see, awesome :D

@everettraven everettraven force-pushed the feature/statussubresource branch 2 times, most recently from 56f9aee to 03bc735 Compare January 20, 2025 18:34
Signed-off-by: Bryce Palmer <bpalmer@redhat.com>
@everettraven everettraven force-pushed the feature/statussubresource branch from 03bc735 to 4ffba8f Compare January 20, 2025 18:35
@JoelSpeed JoelSpeed merged commit 216f465 into kubernetes-sigs:main Jan 21, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants