From 6daf25cfe3c3f908c45c202fc03bbb338beae05a Mon Sep 17 00:00:00 2001 From: Richard Murillo Date: Fri, 6 Mar 2026 16:49:15 -0800 Subject: [PATCH] feat: add large file detection to pre-commit hook Add Test-LargeFiles function to the shared LintHelpers library that checks staged files against configurable thresholds: - Maximum file size: 500 KB (prevents accidental binary/data commits) - Maximum line count: 1000 lines for source files (encourages modular code) The check runs first in the pre-commit hook, before formatting and linting, so oversized files are caught early. Thresholds are configurable via parameters for project-specific needs. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com> --- .githooks/hooks/Invoke-PreCommit.ps1 | 3 ++ .githooks/lib/LintHelpers.ps1 | 59 ++++++++++++++++++++++++++++ CONTRIBUTING.md | 1 + 3 files changed, 63 insertions(+) diff --git a/.githooks/hooks/Invoke-PreCommit.ps1 b/.githooks/hooks/Invoke-PreCommit.ps1 index ddc214c49..ad348bc48 100644 --- a/.githooks/hooks/Invoke-PreCommit.ps1 +++ b/.githooks/hooks/Invoke-PreCommit.ps1 @@ -9,6 +9,9 @@ if ($LASTEXITCODE -ne 0 -or -not $repoRoot) { . "$PSScriptRoot/../lib/LintHelpers.ps1" try { + # Large file detection (file size and line count) + Test-LargeFiles + # C# formatting (auto-fix + re-stage) $csFiles = Get-StagedFiles -Extensions @('.cs') if ($csFiles.Count -gt 0) { diff --git a/.githooks/lib/LintHelpers.ps1 b/.githooks/lib/LintHelpers.ps1 index 7826b4319..a8b266291 100644 --- a/.githooks/lib/LintHelpers.ps1 +++ b/.githooks/lib/LintHelpers.ps1 @@ -97,3 +97,62 @@ function Set-HookFailed { Write-Host "FAIL: $Check" -ForegroundColor Red $script:HookExitCode = 1 } + +function Test-LargeFiles { + <# + .SYNOPSIS + Checks staged files against size and line-count thresholds. + .DESCRIPTION + Prevents accidentally committing oversized files or source files + that have grown beyond a maintainable line count. Binary and + generated files are excluded from the line-count check. + .PARAMETER MaxFileSizeKB + Maximum file size in kilobytes. Default 500 KB. + .PARAMETER MaxLineCount + Maximum number of lines for source files. Default 1000 lines. + .PARAMETER SourceExtensions + File extensions treated as source code for line-count checks. + #> + [CmdletBinding()] + param( + [int]$MaxFileSizeKB = 500, + [int]$MaxLineCount = 1000, + [string[]]$SourceExtensions = @('.cs', '.ps1', '.sh', '.yaml', '.yml', '.json', '.xml', '.md') + ) + + $repoRoot = git rev-parse --show-toplevel + $stagedFiles = git diff --cached --name-only --diff-filter=d + if ($LASTEXITCODE -ne 0 -or -not $stagedFiles) { + return + } + + $maxBytes = $MaxFileSizeKB * 1024 + $violations = @() + + foreach ($file in $stagedFiles) { + $fullPath = Join-Path $repoRoot $file + if (-not (Test-Path $fullPath)) { + continue + } + + $fileInfo = Get-Item $fullPath + if ($fileInfo.Length -gt $maxBytes) { + $sizeKB = [math]::Round($fileInfo.Length / 1024, 1) + $violations += " $file ($($sizeKB) KB exceeds $($MaxFileSizeKB) KB limit)" + } + + $ext = [System.IO.Path]::GetExtension($file) + if ($ext -and $SourceExtensions -contains $ext) { + $lineCount = (Get-Content $fullPath | Measure-Object -Line).Lines + if ($lineCount -gt $MaxLineCount) { + $violations += " $file ($lineCount lines exceeds $MaxLineCount line limit)" + } + } + } + + if ($violations.Count -gt 0) { + Write-Host "Large file(s) detected:" -ForegroundColor Yellow + $violations | ForEach-Object { Write-Host $_ -ForegroundColor Yellow } + Set-HookFailed -Check "large-file-detection" + } +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 73a8df2cc..031f83d18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,6 +57,7 @@ This project adheres to the [Contributor Covenant Code of Conduct](CODE-OF-CONDU | Hook | Check | Mode | Tool | | ------ | ------- | ------ | ------ | + | pre-commit | Large file detection | Fail on error | Built-in (500 KB / 1000 lines) | | pre-commit | C# formatting | Auto-fix + re-stage | `dotnet format` | | pre-commit | Markdown lint | Auto-fix + re-stage | `markdownlint-cli2` | | pre-commit | YAML lint | Lint only | `yamllint` |