-
Notifications
You must be signed in to change notification settings - Fork 482
Add full-repo audit mode to pkg/linters/errormessage #50695
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
4603b21
60c7749
2d73ffd
d523ace
141513d
d75c86c
0f9a7fb
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 |
|---|---|---|
|
|
@@ -24,23 +24,42 @@ var ( | |
| // changedFilesCSV allows CI to scope linting to changed files only, | ||
| // preventing legacy violations from blocking incremental adoption. | ||
| changedFilesCSV string | ||
| // fullRepo enables auditing every analyzed file instead of only the | ||
| // changed ones, so pre-existing violations can be tracked as a metric. | ||
| fullRepo bool | ||
| ) | ||
|
|
||
|
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. [/codebase-design] The 💡 Suggested improvementThis is an inherent limitation of the // NOTE: fullRepo and changedFilesCSV are global package variables bound to
// Analyzer.Flags. Tests that mutate them must reset them via t.Cleanup to
// prevent cross-test pollution.
var (
changedFilesCSV string
fullRepo bool
)Also consider registering the cleanup before any operation that could fail so the reset always runs. @copilot please address this. |
||
| // fullRepoSentinel is the -changed-files value that enables full-repository | ||
| // auditing, equivalent to passing -full-repo. | ||
| const fullRepoSentinel = "all" | ||
|
|
||
| // Analyzer is the errormessage analysis pass. | ||
| var Analyzer = analyzerutil.New("errormessage", "reports non-actionable error message patterns in changed files", run) | ||
| var Analyzer = analyzerutil.New("errormessage", "reports non-actionable error message patterns in changed files (or all files with -full-repo)", run) | ||
|
|
||
| func init() { | ||
| Analyzer.Flags.StringVar(&changedFilesCSV, "changed-files", "", "comma-separated list of changed file paths to lint (when empty, analyzer is a no-op)") | ||
| Analyzer.Flags.StringVar(&changedFilesCSV, "changed-files", "", "comma-separated list of changed file paths to lint (when empty, analyzer is a no-op; use \"all\" to audit every file)") | ||
| Analyzer.Flags.BoolVar(&fullRepo, "full-repo", false, "audit every analyzed file instead of only the changed ones") | ||
| } | ||
|
|
||
| func run(pass *analysis.Pass) (any, error) { | ||
| if fullRepo || isFullRepoSentinel(changedFilesCSV) { | ||
| pkgLog.Printf("analyzing package %s in full-repo mode", pass.Pkg.Path()) | ||
| return runOnFiles(pass, nil) | ||
| } | ||
|
|
||
| changed := parseChangedFiles(changedFilesCSV) | ||
| if len(changed) == 0 { | ||
| pkgLog.Printf("no changed files provided for %s, skipping", pass.Pkg.Path()) | ||
| return nil, nil | ||
| } | ||
| pkgLog.Printf("analyzing package %s (%d changed files)", pass.Pkg.Path(), len(changed)) | ||
|
|
||
| return runOnFiles(pass, changed) | ||
| } | ||
|
|
||
| // runOnFiles analyzes the package. When changed is nil every file is checked | ||
| // (full-repo audit mode); otherwise only files present in changed are checked. | ||
| func runOnFiles(pass *analysis.Pass, changed map[string]struct{}) (any, error) { | ||
| noLintIndex, err := nolint.Index(pass) | ||
| if err != nil { | ||
| return nil, err | ||
|
|
@@ -92,7 +111,18 @@ func parseChangedFiles(csv string) map[string]struct{} { | |
| return changed | ||
| } | ||
|
|
||
| // isFullRepoSentinel reports whether the -changed-files value requests a | ||
| // full-repository audit. | ||
| func isFullRepoSentinel(csv string) bool { | ||
| return strings.EqualFold(strings.TrimSpace(csv), fullRepoSentinel) | ||
| } | ||
|
|
||
| // shouldCheckFile reports whether filename is in scope. A nil changed set means | ||
| // full-repo audit mode, where every file is in scope. | ||
| func shouldCheckFile(filename string, changed map[string]struct{}) bool { | ||
| if changed == nil { | ||
| return true | ||
| } | ||
| path := filepath.ToSlash(filename) | ||
| for changedPath := range changed { | ||
| if path == changedPath || strings.HasSuffix(path, "/"+changedPath) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,3 +22,25 @@ func TestErrorMessage(t *testing.T) { | |
|
|
||
| analysistest.Run(t, analysistest.TestData(), errormessage.Analyzer, "errormessage") | ||
| } | ||
|
|
||
| func TestErrorMessageFullRepoFlag(t *testing.T) { | ||
|
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. [/tdd] The test runs on the same 💡 Suggested fixCreate a separate fixture sub-package (e.g. func TestErrorMessageFullRepoFlag(t *testing.T) {
// fullrepopkg contains a violation not covered by the diff-gated path
analysistest.Run(t, analysistest.TestData(), errormessage.Analyzer, "errormessage/fullrepopkg")
}Without this, the two new tests only confirm the code compiles and branches correctly, not that the full-repo scope expansion actually works end-to-end. @copilot please address this. |
||
| if err := errormessage.Analyzer.Flags.Set("full-repo", "true"); err != nil { | ||
| t.Fatalf("failed to set full-repo flag: %v", err) | ||
| } | ||
| t.Cleanup(func() { | ||
| _ = errormessage.Analyzer.Flags.Set("full-repo", "false") | ||
| }) | ||
|
|
||
| analysistest.Run(t, analysistest.TestData(), errormessage.Analyzer, "errormessage") | ||
| } | ||
|
|
||
| func TestErrorMessageFullRepoSentinel(t *testing.T) { | ||
|
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. [/tdd] In 💡 Recommended patternfunc TestErrorMessageFullRepoSentinel(t *testing.T) {
t.Cleanup(func() { _ = errormessage.Analyzer.Flags.Set("changed-files", "") })
if err := errormessage.Analyzer.Flags.Set("changed-files", "all"); err != nil {
t.Fatalf("failed to set changed-files flag: %v", err)
}
analysistest.Run(t, analysistest.TestData(), errormessage.Analyzer, "errormessage")
}Registering cleanup first ensures it runs even if @copilot please address this. |
||
| if err := errormessage.Analyzer.Flags.Set("changed-files", "all"); err != nil { | ||
| t.Fatalf("failed to set changed-files flag: %v", err) | ||
| } | ||
| t.Cleanup(func() { | ||
| _ = errormessage.Analyzer.Flags.Set("changed-files", "") | ||
| }) | ||
|
|
||
| analysistest.Run(t, analysistest.TestData(), errormessage.Analyzer, "errormessage") | ||
| } | ||
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.
[/grill-with-docs] The binary is built to
/tmp/gh-aw-linters, which is the same path used by the existinggolint-customtarget. If both targets run in the same CI job, the second build overwrites the binary and could cause non-deterministic results.💡 Suggested fix
Use a distinct output path for this target:
@copilot please address this.