Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion buildifier/factory.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def buildifier_attr_factory(*, test_rule):
),
"exclude_patterns": attr.string_list(
allow_empty = True,
doc = "A list of glob patterns passed to the find command. E.g. './vendor/*' to exclude the Go vendor directory. In test rules, this attribute requires the use of the no_sandbox attribute.",
doc = "A list of glob patterns matched like the find command's -path option, on all platforms. E.g. './vendor/*' to exclude the Go vendor directory. In test rules, this attribute requires the use of the no_sandbox attribute.",
),
"mode": attr.string(
default = "fix" if not test_rule else "diff",
Expand Down Expand Up @@ -164,6 +164,7 @@ def buildifier_impl_factory(ctx, *, test_rule):
"{EXCLUDE_PATTERNS}": exclude_patterns_str,
"{FORMAT}": ctx.attr.format,
"{POWERSHELL_ARGS}": _powershell_array_literal(args),
"{POWERSHELL_EXCLUDE_PATTERNS}": _powershell_array_literal(ctx.attr.exclude_patterns),
"{SCAN_WORKSPACE}": "$true" if scan_workspace else "$false",
"{SOURCE_FILES}": _powershell_array_literal(source_files),
"{VERBOSE}": str(ctx.attr.verbose).lower(),
Expand Down
26 changes: 21 additions & 5 deletions runner.bat.template
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ cd /d "%workspace_dir%" || exit /b 1

:workspace_found
REM Keep discovered paths inside PowerShell so cmd.exe never reparses them.
REM Walk the workspace without entering excluded directories, matching each
REM path like find's -path.
REM Process files in batches to stay below CreateProcess' command-line limit,
REM merging per-batch diagnostics when JSON output is requested.
set "BUILDIFIER_EXECUTABLE=%buildifier_path%"
Expand All @@ -59,11 +61,25 @@ powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Comma
"$buildifierArgs = @({POWERSHELL_ARGS});" ^
"$files = @({SOURCE_FILES});" ^
"if ({SCAN_WORKSPACE}) {" ^
"$workspacePrefix = (Get-Location).Path.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar;" ^
"$files = @(Get-ChildItem -LiteralPath . -Recurse -File | Where-Object {" ^
"($env:include_reparse_points -or -not ($_.Attributes -band [IO.FileAttributes]::ReparsePoint)) -and" ^
"$_.Name -cmatch '^(BUILD|WORKSPACE|WORKSPACE\.bzlmod|WORKSPACE\.oss|BUILD\..*\.oss|WORKSPACE\..*\.oss)$|\.(bzl|sky|star|bazel|BUILD)$'" ^
"} | ForEach-Object { $_.FullName.Substring($workspacePrefix.Length) });" ^
"$excludePatterns = @({POWERSHELL_EXCLUDE_PATTERNS});" ^
"$root = (Get-Location).Path;" ^
"$found = New-Object 'System.Collections.Generic.List[string]';" ^
"$pending = New-Object 'System.Collections.Generic.Stack[string]';" ^
"$pending.Push('');" ^
"while ($pending.Count -gt 0) {" ^
"$relativeDir = $pending.Pop();" ^
"foreach ($entry in [IO.DirectoryInfo]::new([IO.Path]::Combine($root, $relativeDir)).EnumerateFileSystemInfos()) {" ^
"if (-not $env:include_reparse_points -and ($entry.Attributes -band [IO.FileAttributes]::ReparsePoint)) { continue };" ^
"$relativePath = if ($relativeDir) { $relativeDir + '/' + $entry.Name } else { $entry.Name };" ^
"$excluded = $false;" ^
"foreach ($pattern in $excludePatterns) { if (('./' + $relativePath) -clike $pattern) { $excluded = $true; break } };" ^
"if ($excluded) { continue };" ^
"if ($entry.Attributes -band [IO.FileAttributes]::Directory) { $pending.Push($relativePath) }" ^
"elseif ($entry.Name -cmatch '^(BUILD|WORKSPACE|WORKSPACE\.bzlmod|WORKSPACE\.oss|BUILD\..*\.oss|WORKSPACE\..*\.oss)$|\.(bzl|sky|star|bazel|BUILD)$') { $found.Add($relativePath.Replace('/', '\')) }" ^
"}" ^
"};" ^
"$found.Sort([StringComparer]::Ordinal);" ^
"$files = @($found);" ^
"};" ^
"if ($files.Count -eq 0) { Write-Error 'Failed to find files to analyze'; exit 1 };" ^
"$jsonOutput = '{FORMAT}' -eq 'json';" ^
Expand Down
46 changes: 46 additions & 0 deletions tests/buildifier/buildifier_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,16 @@ buildifier(
mode = "fix",
)

buildifier(
name = "buildifier.check.exclude",
exclude_patterns = [
"./.git/*",
"./excluded/*",
"./pruned_dir",
],
mode = "diff",
)

buildifier(
name = "buildifier.json",
format = "json",
Expand Down Expand Up @@ -293,6 +303,18 @@ function assert_metacharacter_fixtures_were_fixed() {
assert_equals 15 "${fixture_count}"
}

function create_exclude_fixtures() {
local fixture
for fixture in excluded/BUILD.bazel pruned_dir/sub/BUILD.bazel; do
mkdir -p "$(dirname "${fixture}")"
cat >"${fixture}" << EOF
filegroup(
name="excluded_fixture",
)
EOF
done
}

function create_json_batch_fixtures() {
local index
mkdir -p json_fixtures
Expand Down Expand Up @@ -392,6 +414,30 @@ function test_buildifier_fix_handles_metacharacters() {
assert_metacharacter_fixtures_were_fixed
}

function test_buildifier_check_respects_exclude_patterns() {
local exit_code=0

create_simple_workspace >"${TEST_log}"
bazel run //:buildifier.fix >>"${TEST_log}" 2>&1 || fail "fix exited with non-zero code but should have succeeded"
create_exclude_fixtures

# Without the extra patterns, the fixtures are reported.
bazel run //:buildifier.check >unfiltered-output 2>&1 || exit_code=$?
cat unfiltered-output >>"${TEST_log}"
if [[ ${exit_code} -eq 0 ]]; then
fail "check exited successfully despite unformatted fixtures"
fi
grep -q "excluded" unfiltered-output || fail "fixture in excluded/ was not reported"
grep -q "pruned_dir" unfiltered-output || fail "fixture in pruned_dir/ was not reported"

bazel run //:buildifier.check.exclude >filtered-output 2>&1 ||
fail "check with exclude_patterns exited with non-zero code but should have succeeded"
cat filtered-output >>"${TEST_log}"
if grep -Eq "excluded[/\\]|pruned_dir" filtered-output; then
fail "files matching exclude_patterns were checked"
fi
}

function test_buildifier_json_handles_multiple_windows_batches() {
if ! is_windows; then
echo "SKIPPED windows JSON batching regression"
Expand Down
Loading