@@ -165,13 +165,24 @@ type GeneratedFileInfo struct {
165165// DefaultReviewPolicy returns sensible defaults.
166166func DefaultReviewPolicy () * ReviewPolicy {
167167 return & ReviewPolicy {
168- BlockBreakingChanges : true ,
169- BlockSecrets : true ,
170- FailOnLevel : "error" ,
171- HoldTheLine : true ,
172- SplitThreshold : 50 ,
173- GeneratedPatterns : []string {"*.generated.*" , "*.pb.go" , "*.pb.cc" , "parser.tab.c" , "lex.yy.c" },
174- GeneratedMarkers : []string {"DO NOT EDIT" , "Generated by" , "AUTO-GENERATED" , "This file is generated" },
168+ BlockBreakingChanges : true ,
169+ BlockSecrets : true ,
170+ FailOnLevel : "error" ,
171+ HoldTheLine : true ,
172+ SplitThreshold : 50 ,
173+ GeneratedPatterns : []string {
174+ "*.generated.*" , "*.pb.go" , "*.pb.cc" , "*.pb.h" ,
175+ "parser.tab.c" , "lex.yy.c" ,
176+ "*.swagger.json" , "*.openapi.json" ,
177+ "*_generated.go" , "*_gen.go" ,
178+ "*.min.js" , "*.min.css" ,
179+ },
180+ GeneratedMarkers : []string {
181+ "DO NOT EDIT" , "Generated by" , "AUTO-GENERATED" , "This file is generated" ,
182+ "Code generated" , "Automatically generated" ,
183+ "eslint-disable" , "swagger-codegen" , "openapi-generator" ,
184+ "@generated" , "protoc-gen" , "graphql-codegen" ,
185+ },
175186 CriticalSeverity : "error" ,
176187 DeadCodeMinConfidence : 0.8 ,
177188 TestGapMinLines : 5 ,
@@ -790,10 +801,6 @@ func (e *Engine) checkBreakingChanges(ctx context.Context, opts ReviewPROptions)
790801 }
791802
792803 var findings []ReviewFinding
793- breakingCount := 0
794- if resp .Summary != nil {
795- breakingCount = resp .Summary .BreakingChanges
796- }
797804
798805 for _ , change := range resp .Changes {
799806 if change .Severity == "breaking" || change .Severity == "error" {
@@ -808,6 +815,11 @@ func (e *Engine) checkBreakingChanges(ctx context.Context, opts ReviewPROptions)
808815 }
809816 }
810817
818+ // Filter out rename pairs — a removed + added symbol in the same file
819+ // with the same kind is likely a rename, not a breaking change.
820+ findings = filterRenamePairs (findings )
821+ breakingCount := len (findings )
822+
811823 status := "pass"
812824 severity := "error"
813825 summary := "No breaking API changes"
@@ -825,6 +837,43 @@ func (e *Engine) checkBreakingChanges(ctx context.Context, opts ReviewPROptions)
825837 }, findings
826838}
827839
840+ // filterRenamePairs removes findings that are likely renames rather than
841+ // breaking changes. A rename produces "removed X" + "added Y" in the same
842+ // file with the same kind — not a real API break.
843+ func filterRenamePairs (findings []ReviewFinding ) []ReviewFinding {
844+ // Group by file
845+ byFile := make (map [string ][]ReviewFinding )
846+ for _ , f := range findings {
847+ byFile [f .File ] = append (byFile [f .File ], f )
848+ }
849+
850+ var filtered []ReviewFinding
851+ for _ , fileFindings := range byFile {
852+ // Count removed and added per kind
853+ removedByKind := make (map [string ]int )
854+ addedByKind := make (map [string ]int )
855+ for _ , f := range fileFindings {
856+ if strings .Contains (f .Message , "removed" ) || strings .Contains (f .Message , "Removed" ) {
857+ removedByKind [f .RuleID ]++
858+ } else if strings .Contains (f .Message , "added" ) || strings .Contains (f .Message , "Added" ) || strings .Contains (f .Message , "new" ) {
859+ addedByKind [f .RuleID ]++
860+ }
861+ }
862+
863+ for _ , f := range fileFindings {
864+ kind := f .RuleID
865+ isRemoved := strings .Contains (f .Message , "removed" ) || strings .Contains (f .Message , "Removed" )
866+ // If there's a matching add for this remove in the same file+kind, skip it
867+ if isRemoved && addedByKind [kind ] > 0 {
868+ addedByKind [kind ]--
869+ continue // Likely a rename
870+ }
871+ filtered = append (filtered , f )
872+ }
873+ }
874+ return filtered
875+ }
876+
828877func (e * Engine ) checkSecrets (ctx context.Context , files []string ) (ReviewCheck , []ReviewFinding ) {
829878 start := time .Now ()
830879
0 commit comments