-
Notifications
You must be signed in to change notification settings - Fork 23
Add noreferences linter #163
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?
Conversation
|
Welcome @krishagarwal278! |
a2cce44 to
4e54c0c
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.
This is a great start, thanks for your contribution!
docs/linters.md
Outdated
| ```yaml | ||
| lintersConfig: | ||
| references: | ||
| allowRefAndRefs: false | true # Allow Ref/Refs suffixes for OpenShift compatibility. Defaults to `false`. |
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.
We generally prefer enums over bools, so maybe lets change this to be more like policy config like we have in other places. Perhaps the values could be AllowRefAndRefs and ForbidRefAndRefs?
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.
Nit: Let's also drop the OpenShift mention. This is a vendor-neutral project.
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 i agree. Having policy config in an enum would make a lot more sense. Incorporated in latest commit 👍🏻
docs/linters.md
Outdated
| **OpenShift compatibility (allowRefAndRefs=true):** | ||
| - Reports errors for fields ending with 'Reference' or 'References' | ||
| - Allows fields ending with 'Ref' or 'Refs' without reporting errors |
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.
In this mode we want to also report Ref and Refs and drop all of these
| @@ -0,0 +1,22 @@ | |||
| package a | |||
|
|
|||
| type TestSpec struct { | |||
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.
Can you try some field names where they contain the string ref/refs or reference/references but not at the end? Eg Prefix or Prefereneces perhaps could be in field names?
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.
across both 'a' and 'b' test files i incorporated tests for prefix, suffix, middle of the field and edge cases 👍🏻
pkg/analysis/references/analyzer.go
Outdated
| func (a *analyzer) checkField(pass *analysis.Pass, field *ast.Field, jsonTagInfo extractjsontags.FieldTagInfo) { | ||
| if field == nil || len(field.Names) == 0 { | ||
| return | ||
| } | ||
|
|
||
| fieldName := utils.FieldName(field) | ||
|
|
||
| if strings.HasSuffix(fieldName, "Reference") { | ||
| suggestedName := strings.TrimSuffix(fieldName, "Reference") + "Ref" | ||
| pass.Report(analysis.Diagnostic{ | ||
| Pos: field.Pos(), | ||
| Message: fmt.Sprintf("field %s should use 'Ref' instead of 'Reference'", fieldName), | ||
| SuggestedFixes: []analysis.SuggestedFix{ | ||
| { | ||
| Message: "replace 'Reference' with 'Ref'", | ||
| TextEdits: []analysis.TextEdit{ | ||
| { | ||
| Pos: field.Names[0].Pos(), | ||
| NewText: []byte(suggestedName), | ||
| End: field.Names[0].End(), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| return | ||
| } | ||
|
|
||
| if strings.HasSuffix(fieldName, "References") { | ||
| suggestedName := strings.TrimSuffix(fieldName, "References") + "Refs" | ||
| pass.Report(analysis.Diagnostic{ | ||
| Pos: field.Pos(), | ||
| Message: fmt.Sprintf("field %s should use 'Refs' instead of 'References'", fieldName), | ||
| SuggestedFixes: []analysis.SuggestedFix{ | ||
| { | ||
| Message: "replace 'References' with 'Refs'", | ||
| TextEdits: []analysis.TextEdit{ | ||
| { | ||
| Pos: field.Names[0].Pos(), | ||
| NewText: []byte(suggestedName), | ||
| End: field.Names[0].End(), | ||
| }, | ||
| }, | ||
| }, | ||
| }, | ||
| }) | ||
| return | ||
| } | ||
|
|
||
| // If allowRefAndRefs is false, report errors for standalone Ref/Refs fields | ||
| // If allowRefAndRefs is true (OpenShift), don't report errors for Ref/Refs fields | ||
| if !a.allowRefAndRefs { | ||
| // Check for fields ending with Ref or Refs (excluding those already handled above) | ||
| if fieldName != "Ref" && strings.HasSuffix(fieldName, "Ref") && !strings.HasSuffix(fieldName, "eRef") { | ||
| pass.Reportf(field.Pos(), "field %s should not use 'Ref' suffix", fieldName) | ||
| } | ||
|
|
||
| if fieldName != "Refs" && strings.HasSuffix(fieldName, "Refs") && !strings.HasSuffix(fieldName, "eRefs") { | ||
| pass.Reportf(field.Pos(), "field %s should not use 'Refs' suffix", fieldName) | ||
| } | ||
| } | ||
| } |
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 is all very well written, but, take a look at the namingconventions linter. I believe we can implement this linter as a wrapper around that linter just by providing it with fixed configuration based on the config rules for this particular linter.
| lintersConfig: | ||
|
|
||
| references: {} | ||
|
|
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.
NIt, probably best to remove the blank lines in these code blocks
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.
Not yet actioned
|
|
||
| // validateConfig validates the configuration for the references linter. | ||
| func validateConfig(cfg *Config, fldPath *field.Path) field.ErrorList { | ||
| // No validation needed for this simple config |
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.
If we switch to an enum, I'd expect some validation here FWIW
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.
policy validation incorporated 👍🏻
.golangci.yaml
Outdated
| - govet | ||
| - importas | ||
| - ineffassign | ||
| - kubeapilinter |
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.
Huh? 👀
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.
Reverted that change 👍🏻 can't have kubeapilinter as a linter itself for this project 😆
Was testing out/exploring different files in the linter and so might've committed this as a change too
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 want more test cases about references linter. And you mention OpenShift, but I think kube-api-linter should provide better practices for all developer who design Kubernetes API. Though original issue says OpenShift, I think it's better to publish this linter more general.
docs/linters.md
Outdated
| - Reports errors for fields ending with 'Reference' or 'References' | ||
| - Also reports errors for fields ending with 'Ref' or 'Refs' (unless they were corrected from Reference/References) | ||
|
|
||
| **OpenShift compatibility (allowRefAndRefs=true):** |
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.
OpenShift compatibility
Is this unique problem with OpenShift ? Other projects might use this option, so I suggest to rename this to more general.
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.
Not unique to Openshift. Removed mention 👍🏻
pkg/analysis/references/analyzer.go
Outdated
| if fieldName != "Ref" && strings.HasSuffix(fieldName, "Ref") && !strings.HasSuffix(fieldName, "eRef") { | ||
| pass.Reportf(field.Pos(), "field %s should not use 'Ref' suffix", fieldName) | ||
| } | ||
|
|
||
| if fieldName != "Refs" && strings.HasSuffix(fieldName, "Refs") && !strings.HasSuffix(fieldName, "eRefs") { | ||
| pass.Reportf(field.Pos(), "field %s should not use 'Refs' suffix", fieldName) | ||
| } |
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 is eRef and eRefs ? why do we check the field with it ? Isn't it enough to only check Ref or Refs ?
I want some examples for test.
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.
replaced the initially added condition to check for letters/patterns before or after. Incorporated edge cases in test files 👍🏻
docs/linters.md
Outdated
|
|
||
| **Default behavior (allowRefAndRefs=false):** | ||
| - Reports errors for fields ending with 'Reference' or 'References' | ||
| - Also reports errors for fields ending with 'Ref' or 'Refs' (unless they were corrected from Reference/References) |
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.
It says “suffix,” but does that mean it doesn't allow fields named Ref or Refs?
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.
removed "suffix" as we are replacing instances of 'Reference' and 'References' anywhere across the field. beginning(prefix), middle, end
docs/linters.md
Outdated
|
|
||
| The `references` linter ensures that field names use 'Ref'/'Refs' instead of 'Reference'/'References'. | ||
|
|
||
| By default, `references` is enabled and operates in strict mode, prohibiting the use of 'Reference', 'References', 'Ref', or 'Refs' anywhere in field names |
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.
Default should be to allow Ref/Refs, but not Reference/References
docs/linters.md
Outdated
| ``` | ||
|
|
||
| **Default behavior (policy: ForbidRefAndRefs):** | ||
| - Reports errors for fields containing 'Reference' or 'References' anywhere and suggests replacing with 'Ref' or 'Refs' |
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.
Why would it suggest to replace with something that it will then report is bad?
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.
Yikes, i guess I misunderstood the default policy to be forbidRefAndRefs. It's now allowRefAndRefs which makes sense because we want to allow Ref and Refs but not Reference and References as the default configuration option
| // NewAnalyzer creates a new analysis.Analyzer for the namingconventions | ||
| // linter based on the provided config. | ||
| func newAnalyzer(cfg *Config) *analysis.Analyzer { | ||
| // This function is exported to allow other linters to wrap namingconventions | ||
| // with fixed configuration. | ||
| func NewAnalyzer(cfg *Config) *analysis.Analyzer { |
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.
Are we certain this needs to be changed to exported? I thought we avoided that on the other PR
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.
Ahh nice catch. Guess we can avoid it here too!
pkg/analysis/references/analyzer.go
Outdated
| // Match "Refs" but not when part of "References" | ||
| namingconventions.Convention{ | ||
| Name: "forbid-refs", | ||
| ViolationMatcher: "Refs([^a-z]|$)", |
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.
Refs would not be part of references? I don't think the extra capture is needed here is it?
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 was part of forbidRefAndRefs policy
pkg/analysis/references/analyzer.go
Outdated
|
|
||
| // If policy is ForbidRefAndRefs, add conventions to forbid Ref/Refs anywhere | ||
| // Exclude patterns already handled by Reference/References above | ||
| if policy == PolicyForbidRefAndRefs { |
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 think it might make sense rather to append, to look into replace the list in this case (probably switch on the valid values?) and then look at how you could regex Reference Ref References and Refs` in a single regex for the drop
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.
Appending into a single regex for this makes so much sense!
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.
Agreed, a single regex makes sense here.
| var errs field.ErrorList | ||
|
|
||
| // Validate Policy enum if provided | ||
| if cfg.Policy != "" && cfg.Policy != PolicyAllowRefAndRefs && cfg.Policy != PolicyForbidRefAndRefs { |
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.
Better to use a switch here and have the default case error
| lintersConfig: | ||
|
|
||
| references: {} | ||
|
|
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.
Not yet actioned
pkg/analysis/references/config.go
Outdated
|
|
||
| // Config represents the configuration for the references linter. | ||
| type Config struct { | ||
| // Policy controls whether Ref/Refs are allowed or forbidden in field names. |
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.
For consistency with other rules
| // Policy controls whether Ref/Refs are allowed or forbidden in field names. | |
| // policy controls whether Ref/Refs are allowed or forbidden in field names. |
| ConfigRefs []string `json:"configRefs"` // want `naming convention "references-to-refs": field ConfigReferences: field names should use 'Refs' instead of 'References'` | ||
|
|
||
| // Fields with Reference at beginning should be flagged | ||
| RefCount int `json:"referenceCount"` // want `naming convention "reference-to-ref": field ReferenceCount: field names should use 'Ref' instead of 'Reference'` |
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.
Should it not also have fixed the json?
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.
When testing locally, it's also fixing json. Latest commit has the new version of the file 👍🏻
pkg/analysis/references/analyzer.go
Outdated
| namingconventions.Convention{ | ||
| Name: "forbid-refs", | ||
| ViolationMatcher: "Refs([^a-z]|$)", | ||
| Operation: namingconventions.OperationInform, |
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.
Should this be a Drop rather than inform?
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 think we should just inform here because user wants to flag / forbidRefAndRefs they may not necessarily want to drop that substring itself.
For eg: We might not want NodeRef --> Node
dropping/swapping out ref(s) could be in scope for another story 👍🏻
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, happy to have this as inform for now, will see if we get any feedback about it
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.
Not sure I agree here. I think intention behind forbidRefAndRefs is actually to cause something like NodeRef -> Node.
If we think there is a reasonable use case to inform instead of suggest fixes, maybe we follow configuration precedence of other linters to allow a Warn and SuggestFixes configuration for this linter and we default to SuggestFixes?
|
/label tide/merge-method-squash |
docs/linters.md
Outdated
| - **Allows** fields containing 'Ref' or 'Refs' without reporting errors | ||
|
|
||
| **Strict mode (policy: ForbidRefAndRefs):** | ||
| - Reports errors for fields containing 'Reference' or 'References' anywhere and suggests replacing with 'Ref' or 'Refs' |
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 behaviour feels wrong still, suggesting to replace something that will then flag again?
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.
+1, this should be dropping of the offending text.
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.
@JoelSpeed @everettraven if y'all agree to dropping Ref/s too as offending text in ForbidRefAndRefs, can certainly make that change 👍🏻
docs/linters.md
Outdated
| - `NodeReferences` → `NodeRefs` | ||
|
|
||
| Note: In the default `ForbidRefAndRefs` mode, these fixes are intermediate - the linter will still report errors on the resulting 'Ref'/'Refs' patterns, indicating they should be removed entirely | ||
| Note: In the `ForbidRefAndRefs` mode, the fixes are intermediate. As, the linter will still report errors on the resulting 'Ref'/'Refs' patterns, indicating they should be removed entirely |
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 think we can avoid this
pkg/analysis/references/analyzer.go
Outdated
| conventions := []namingconventions.Convention{ | ||
| { | ||
| Name: "reference-to-ref", | ||
| ViolationMatcher: "(?i)reference(s?)", |
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.
Why do we make this case insensitive? Isn't that causing things like Preference to become Prefs, I don't think that's actually desired? I think we are better not having the case insensitivity aren't we?
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.
Hmm. That's a good question - I can't remember if removing the case sensitivity would mean we don't update the serialized form of the name correctly or not.
Would be good to double check that. If it still handles serialized name updates correctly, I agree we can put this back to being case sensitive.
Doing that means we do miss cases where the field name casing is incorrect though like Podreferences.
I wonder if adding a linter specifically for field name being PascalCase would make sense and consider something like Podreferences to be out of scope here?
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.
+1 @JoelSpeed i agree on making it case sensitive. Currently we are getting false positives as its converting Preference to Prefs which is documented as a known limitation.
@everettraven Circling back to our last discussion on PascalCase i still do feel that adding another linter for field name being PascalCase would make most sense.
We can possibly flag instances likePodreferences, referenceCount here to say field has invalid casing.
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.
@krishagarwal278 Could you verify that removing the case insensitivity results in successfully matching the json tags that look like reference* and *Reference?
pkg/analysis/references/analyzer.go
Outdated
| // If policy is ForbidRefAndRefs, also flag Ref/Refs as problematic (no fix provided) | ||
| // This creates a two-step hint: fix Reference→Ref, but know that Ref also needs changing | ||
| if policy == PolicyForbidRefAndRefs { | ||
| conventions = append(conventions, |
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 think this wants to replace, not append. That way we can avoid the intermediate steps.
Should be able to just have a single regex here I think
pkg/analysis/references/analyzer.go
Outdated
| namingconventions.Convention{ | ||
| Name: "forbid-refs", | ||
| ViolationMatcher: "Refs([^a-z]|$)", | ||
| Operation: namingconventions.OperationInform, |
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, happy to have this as inform for now, will see if we get any feedback about it
docs/linters.md
Outdated
| ```yaml | ||
| lintersConfig: | ||
| references: | ||
| policy: AllowRefAndRefs | ForbidRefAndRefs # Defaults to `AllowRefAndRefs`. |
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.
Probably more of a nitpick, but I wonder if something like PreferAbbreviatedReference and NoReference might be a bit more intuitive naming from the end-user perspective?
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.
Naming suggestion works for me
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.
Nit: I think @JoelSpeed i agreed on something like PreferAbbreviatedReference and NoReferences
docs/linters.md
Outdated
| - **Allows** fields containing 'Ref' or 'Refs' without reporting errors | ||
|
|
||
| **Strict mode (policy: ForbidRefAndRefs):** | ||
| - Reports errors for fields containing 'Reference' or 'References' anywhere and suggests replacing with 'Ref' or 'Refs' |
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.
+1, this should be dropping of the offending text.
pkg/analysis/references/analyzer.go
Outdated
| conventions := []namingconventions.Convention{ | ||
| { | ||
| Name: "reference-to-ref", | ||
| ViolationMatcher: "(?i)reference(s?)", |
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.
Hmm. That's a good question - I can't remember if removing the case sensitivity would mean we don't update the serialized form of the name correctly or not.
Would be good to double check that. If it still handles serialized name updates correctly, I agree we can put this back to being case sensitive.
Doing that means we do miss cases where the field name casing is incorrect though like Podreferences.
I wonder if adding a linter specifically for field name being PascalCase would make sense and consider something like Podreferences to be out of scope here?
pkg/analysis/references/analyzer.go
Outdated
|
|
||
| // If policy is ForbidRefAndRefs, add conventions to forbid Ref/Refs anywhere | ||
| // Exclude patterns already handled by Reference/References above | ||
| if policy == PolicyForbidRefAndRefs { |
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.
Agreed, a single regex makes sense here.
pkg/analysis/references/analyzer.go
Outdated
| namingconventions.Convention{ | ||
| Name: "forbid-refs", | ||
| ViolationMatcher: "Refs([^a-z]|$)", | ||
| Operation: namingconventions.OperationInform, |
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.
Not sure I agree here. I think intention behind forbidRefAndRefs is actually to cause something like NodeRef -> Node.
If we think there is a reasonable use case to inform instead of suggest fixes, maybe we follow configuration precedence of other linters to allow a Warn and SuggestFixes configuration for this linter and we default to SuggestFixes?
docs/linters.md
Outdated
|
|
||
| ## References | ||
|
|
||
| The `references` linter ensures that field names use 'Ref'/'Refs' instead of 'Reference'/'References'. |
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.
It looks like we've established a pattern that for linters associated with a "don't do this" semantic we prefix with no.
I think staying consistent would be good, so I wonder if this should instead be noreference?
@JoelSpeed what are your thoughts here?
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.
Yeah I think that makes sense, noreference or noreferences
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 only pushback I can think of on that, is that the others are forbidding the usage of certain types. Which means this one forbidding just the naming might be a bit different? Does it imply that you aren't allowed reference types vs fields with references in the name?
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.
We have nophase and notimestamp which are naming conventions
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.
Ok, @krishagarwal278 can you rename this to noreferences please
pkg/analysis/references/analyzer.go
Outdated
| } | ||
|
|
||
| default: | ||
| // Should not happen due to validation, but return PreferAbbreviatedReference conventions as fallback |
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.
In this case it's suitable to panic
|
|
||
| // Edge cases - Preference contains "reference" and WILL be flagged with (?i) | ||
| // This is intentional to catch all variations including malformed casing | ||
| PreferenceType string `json:"preferenceType"` // want `naming convention "reference-to-ref": field PreferenceType: field names should use 'Ref' instead of 'Reference'` |
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 think using an adaptation of the regex for the prefer abbreviated functionality, we should be able to avoid this edge case.
Think about how we can require upper or lower at the beginning (^) vs requiring upper when not at the beginning
Right @everettraven ? I think that's what you were aiming for
pkg/analysis/references/analyzer.go
Outdated
| return []namingconventions.Convention{ | ||
| { | ||
| Name: "no-references", | ||
| ViolationMatcher: "^([Rr]ef(?:erence)?s?)([A-Z])|([Rr]ef(?:erence)?s?)$", |
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.
| ViolationMatcher: "^([Rr]ef(?:erence)?s?)([A-Z])|([Rr]ef(?:erence)?s?)$", | |
| ViolationMatcher: "^([Rr]ef(?:erence)?s?)([A-Z])|(Ref(?:erence)?s?)$", |
Shouldn't the second part of this not be case insensitive?
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.
Yeah possibly. Do you also suggest making the first part case insensitive for consistency?
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 believe the first part is deliberate to pick up fields starting with Reference, cc @everettraven since I think he came up with this regex
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 doesn't look quite like the one I came up with, but you probably want 2 variants here based on the configured policy (i.e preferring Ref vs none at all).
If you prefer Ref(s), it should look something like:
^[Rr]eferences?|References?$
The first half of the expression, ^[Rr]eferences?, will match any fields that follow the pattern Reference*, References*, reference*, and References*.
The second half of the expression, References?$ will match any fields that follow the pattern *Reference and *References. This prevents if from picking up things like *Preferences because it doesn't match on the lowercase r.
If want neither Ref nor References, it should look something like:
^[Rr]ef(erence)?s?|Ref(erence)?s?$
This does generally the same thing as the previous expression, but makes the erence part of Reference optional in the matching. That means it will additionally match Ref*, ref*, Refs*, refs*, *Ref, and *Refs.
docs/linters.md
Outdated
|
|
||
| ## References | ||
|
|
||
| The `references` linter ensures that field names use 'Ref'/'Refs' instead of 'Reference'/'References'. |
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.
Ok, @krishagarwal278 can you rename this to noreferences please
docs/linters.md
Outdated
| - [Notimestamp](#notimestamp) - Prevents usage of 'TimeStamp' fields | ||
| - [OptionalFields](#optionalfields) - Validates optional field conventions | ||
| - [OptionalOrRequired](#optionalorrequired) - Ensures fields are explicitly marked as optional or required | ||
| - [References](#references) - Ensures field names use Ref/Refs instead of Reference/References |
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.
| - [References](#references) - Ensures field names use Ref/Refs instead of Reference/References | |
| - [NoReferences](#noreferences) - Ensures field names use Ref/Refs instead of Reference/References |
|
|
||
| case PolicyNoReferences: | ||
| // Drop any reference-related words from field names | ||
| // At start: matches [Rr]ef(erence)?s? followed by uppercase letter, preserving that letter ($2) |
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.
| // At start: matches [Rr]ef(erence)?s? followed by uppercase letter, preserving that letter ($2) | |
| // At start: matches [Rr]ef(erence)?s? followed by uppercase letter, preserving that letter ($3) |
| // When at start, $2 captures and preserves the next uppercase letter | ||
| // When at end, $2 is empty, effectively dropping the text |
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.
| // When at start, $2 captures and preserves the next uppercase letter | |
| // When at end, $2 is empty, effectively dropping the text | |
| // When at start, $3 captures and preserves the next uppercase letter | |
| // When at end, $3 is empty, effectively dropping the text |
pkg/analysis/noreferences/doc.go
Outdated
| lintersConfig: | ||
| noreferences: | ||
| policy: PreferAbbreviatedReference | ||
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.
| lintersConfig: | |
| noreferences: | |
| policy: PreferAbbreviatedReference | |
| lintersConfig: | |
| noreferences: | |
| policy: PreferAbbreviatedReference |
| noreferences: | ||
| policy: NoReferences | ||
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.
| noreferences: | |
| policy: NoReferences | |
| noreferences: | |
| policy: NoReferences |
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.
formatting for the markdown codeblock is finicky. didn't realize closing the file after making changes, will autosaved and added that extra line again but it's adding some extra indentation on lintersConfig. I replaced it with multi-line comment to preserve my changes 👍🏻
golangci-lint-kube-api-linter
Outdated
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 should not be committed
docs/linters.md
Outdated
| - `RefNode` → `Node` (start) | ||
| - `NodeRef` → `Node` (end) | ||
| - `ReferenceName` → `Name` (start) | ||
| - `ConfigReferences` → `Config` (end) |
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.
Looking at the test, I believe the s is preserved isn't it?
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.
currently we're not preserving s because References to a Config can't change to Configs. At the moment we're dropping reference/references but it doesn't impact/change Config itself.
Another example from the b.go and b.go.golden
- ContainerRefs []string `json:"containerRefs"`
- Container []string `json:"container"` // want `naming convention "no-references": field ContainerRefs: field names should not contain reference-related words`
3fe6ca1 to
e910b22
Compare
| Name: "reference-to-ref", | ||
| ViolationMatcher: "^[Rr]eference(s?)|Reference(s?)$", | ||
| Operation: namingconventions.OperationReplacement, | ||
| Replacement: "Ref$1$2", |
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.
There's only 1 capture group in the regex isn't there? Should be this?
| Replacement: "Ref$1$2", | |
| Replacement: "Ref$1", |
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: JoelSpeed, krishagarwal278 The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
d55c401 to
9b85f8b
Compare
9b85f8b to
7afeb87
Compare
| case PolicyPreferAbbreviatedReference: | ||
| // Replace "Reference" or "References" with "Ref" or "Refs" anywhere in field name | ||
| // Case insensitive to handle lowercase in JSON tags | ||
| // Note: May produce false positives like "Preference" → "PRef", but this is acceptable |
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 think this line is not actually true anymore
7afeb87 to
4ab5c7c
Compare
|
/lgtm |
| @@ -1,6 +1,9 @@ | |||
| package defaultconfigurations | |||
|
|
|||
| import "k8s.io/apimachinery/pkg/types" | |||
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 appears to have broken the integration tests
ca49477 to
7078b02
Compare
7078b02 to
360add3
Compare
fc1d183 to
360add3
Compare
|
/ok-to-test |
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.
One minor comment on the go doc for the linter.
Other than that, this LGTM.
@krishagarwal278 mentioned that tagging with an LGTM seems to kick the GHA workflows - giving this a shot. If this merges with the documentation comment we can follow up with a PR to fix it.
/lgtm
pkg/analysis/noreferences/doc.go
Outdated
| /* | ||
| The `noreferences` linter ensures that field names use 'Ref'/'Refs' instead of 'Reference'/'References'. | ||
| By default, `noreferences` is enabled and enforces this naming convention. | ||
| The linter checks that 'Reference' anywhere in field names (beginning, middle, or end) is replaced with 'Ref'. |
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.
Only beginning and end right?
|
Doesn't look like that is the case. /lgtm cancel |
299b4b0 to
e6f037a
Compare
e6f037a to
6fd4884
Compare
Added a new references linter to enforce that API field names use Ref/Refs suffixes instead of Reference/References.
What it does:
Fixes #25