mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-29 05:02:04 +03:00
fix: improve code-size gate output and duplicate detection, fix Windows path in source-display
This commit is contained in:
@@ -40,33 +40,20 @@ SKIP_SHORT_PATTERNS = {
|
|||||||
}
|
}
|
||||||
SKIP_SHORT_SUFFIXES = ('-cli.ts',)
|
SKIP_SHORT_SUFFIXES = ('-cli.ts',)
|
||||||
|
|
||||||
# Function names to skip in duplicate detection (common utilities, test helpers)
|
# Function names to skip in duplicate detection.
|
||||||
|
# Only list names so generic they're expected to appear independently in many modules.
|
||||||
|
# Do NOT use prefix-based skipping — it hides real duplication (e.g. formatDuration,
|
||||||
|
# stripPrefix, parseConfig are specific enough to flag).
|
||||||
SKIP_DUPLICATE_FUNCTIONS = {
|
SKIP_DUPLICATE_FUNCTIONS = {
|
||||||
# Common utility names
|
# Lifecycle / framework plumbing
|
||||||
'main', 'init', 'setup', 'teardown', 'cleanup', 'dispose', 'destroy',
|
'main', 'init', 'setup', 'teardown', 'cleanup', 'dispose', 'destroy',
|
||||||
'open', 'close', 'connect', 'disconnect', 'execute', 'run', 'start', 'stop',
|
'open', 'close', 'connect', 'disconnect', 'execute', 'run', 'start', 'stop',
|
||||||
'render', 'update', 'refresh', 'reset', 'clear', 'flush',
|
'render', 'update', 'refresh', 'reset', 'clear', 'flush',
|
||||||
|
# Too-short / too-generic identifiers
|
||||||
|
'text', 'json', 'pad', 'mask', 'digest', 'confirm', 'intro', 'outro',
|
||||||
|
'exists', 'send', 'receive', 'listen', 'log', 'warn', 'error', 'info',
|
||||||
|
'help', 'version', 'config', 'configure', 'describe', 'test', 'action',
|
||||||
}
|
}
|
||||||
|
|
||||||
SKIP_DUPLICATE_PREFIXES = (
|
|
||||||
# Transformers
|
|
||||||
'normalize', 'parse', 'validate', 'serialize', 'deserialize',
|
|
||||||
'convert', 'transform', 'extract', 'encode', 'decode',
|
|
||||||
# Predicates
|
|
||||||
'is', 'has', 'can', 'should', 'will',
|
|
||||||
# Constructors/factories
|
|
||||||
'create', 'make', 'build', 'generate', 'new',
|
|
||||||
# Accessors
|
|
||||||
'get', 'set', 'read', 'write', 'load', 'save', 'fetch',
|
|
||||||
# Handlers
|
|
||||||
'handle', 'on', 'emit',
|
|
||||||
# Modifiers
|
|
||||||
'add', 'remove', 'delete', 'update', 'insert', 'append',
|
|
||||||
# Other common
|
|
||||||
'to', 'from', 'with', 'apply', 'process', 'resolve', 'ensure', 'check',
|
|
||||||
'filter', 'map', 'reduce', 'merge', 'split', 'join', 'find', 'search',
|
|
||||||
'register', 'unregister', 'subscribe', 'unsubscribe',
|
|
||||||
)
|
|
||||||
SKIP_DUPLICATE_FILE_PATTERNS = ('.test.ts', '.test.tsx', '.spec.ts')
|
SKIP_DUPLICATE_FILE_PATTERNS = ('.test.ts', '.test.tsx', '.spec.ts')
|
||||||
|
|
||||||
# Known packages in the monorepo
|
# Known packages in the monorepo
|
||||||
@@ -150,12 +137,33 @@ def find_duplicate_functions(files: List[Tuple[Path, int]], root_dir: Path) -> D
|
|||||||
# Skip known common function names
|
# Skip known common function names
|
||||||
if func in SKIP_DUPLICATE_FUNCTIONS:
|
if func in SKIP_DUPLICATE_FUNCTIONS:
|
||||||
continue
|
continue
|
||||||
if any(func.startswith(prefix) for prefix in SKIP_DUPLICATE_PREFIXES):
|
|
||||||
continue
|
|
||||||
function_locations[func].append(file_path)
|
function_locations[func].append(file_path)
|
||||||
|
|
||||||
# Filter to only duplicates
|
# Filter to only duplicates, ignoring cross-extension duplicates.
|
||||||
return {name: paths for name, paths in function_locations.items() if len(paths) > 1}
|
# Extensions are independent packages — the same function name in
|
||||||
|
# extensions/telegram and extensions/discord is expected, not duplication.
|
||||||
|
result: Dict[str, List[Path]] = {}
|
||||||
|
for name, paths in function_locations.items():
|
||||||
|
if len(paths) < 2:
|
||||||
|
continue
|
||||||
|
# If ALL instances are in different extensions, skip
|
||||||
|
ext_dirs = set()
|
||||||
|
non_ext = False
|
||||||
|
for p in paths:
|
||||||
|
try:
|
||||||
|
rel = p.relative_to(root_dir)
|
||||||
|
parts = rel.parts
|
||||||
|
if len(parts) >= 2 and parts[0] == 'extensions':
|
||||||
|
ext_dirs.add(parts[1])
|
||||||
|
else:
|
||||||
|
non_ext = True
|
||||||
|
except ValueError:
|
||||||
|
non_ext = True
|
||||||
|
# Skip if every instance lives in a different extension (no core overlap)
|
||||||
|
if not non_ext and len(ext_dirs) == len(paths):
|
||||||
|
continue
|
||||||
|
result[name] = paths
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def validate_git_ref(root_dir: Path, ref: str) -> bool:
|
def validate_git_ref(root_dir: Path, ref: str) -> bool:
|
||||||
@@ -285,8 +293,6 @@ def find_duplicate_regressions(
|
|||||||
for func in functions:
|
for func in functions:
|
||||||
if func in SKIP_DUPLICATE_FUNCTIONS:
|
if func in SKIP_DUPLICATE_FUNCTIONS:
|
||||||
continue
|
continue
|
||||||
if any(func.startswith(prefix) for prefix in SKIP_DUPLICATE_PREFIXES):
|
|
||||||
continue
|
|
||||||
base_function_locations[func].append(file_path)
|
base_function_locations[func].append(file_path)
|
||||||
|
|
||||||
base_dupes = {name for name, paths in base_function_locations.items() if len(paths) > 1}
|
base_dupes = {name for name, paths in base_function_locations.items() if len(paths) > 1}
|
||||||
@@ -432,7 +438,28 @@ def main():
|
|||||||
|
|
||||||
print()
|
print()
|
||||||
if args.strict and violations:
|
if args.strict and violations:
|
||||||
|
# Print actionable summary so contributors know what to do
|
||||||
|
print("─" * 60)
|
||||||
|
print("❌ Code size check failed\n")
|
||||||
|
if crossed:
|
||||||
|
print(f" {len(crossed)} file(s) grew past the {args.threshold}-line limit.")
|
||||||
|
if grew:
|
||||||
|
print(f" {len(grew)} file(s) already over {args.threshold} lines got larger.")
|
||||||
|
print()
|
||||||
|
print(" How to fix:")
|
||||||
|
print(" • Split large files into smaller, focused modules")
|
||||||
|
print(" • Extract helpers, types, or constants into separate files")
|
||||||
|
print(" • See AGENTS.md for guidelines (~500-700 LOC target)")
|
||||||
|
print()
|
||||||
|
print(f" This check compares your PR against {args.compare_to}.")
|
||||||
|
print(f" Only code files are checked ({', '.join(sorted(e for e in CODE_EXTENSIONS))}).")
|
||||||
|
print(" Docs, tests names, and config files are not affected.")
|
||||||
|
print("─" * 60)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
elif args.strict:
|
||||||
|
print("─" * 60)
|
||||||
|
print("✅ Code size check passed — no files exceed thresholds.")
|
||||||
|
print("─" * 60)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ function tryRelative(root: string, filePath: string): string | null {
|
|||||||
if (path.isAbsolute(rel)) {
|
if (path.isAbsolute(rel)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return rel;
|
// Normalize to forward slashes for display (path.relative uses backslashes on Windows)
|
||||||
|
return rel.replaceAll("\\", "/");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolvePluginSourceRoots(params: { workspaceDir?: string }): PluginSourceRoots {
|
export function resolvePluginSourceRoots(params: { workspaceDir?: string }): PluginSourceRoots {
|
||||||
|
|||||||
Reference in New Issue
Block a user