Migrate formatting toolchain from dotnet format to curb - #3904
Open
Mpdreamz wants to merge 6 commits into
Open
Conversation
Adds curb 0.2.0 as a GlobalPackageReference (MSBuild integration that auto-rewrites on Debug builds and fails on Release/CI) and curb-cli 0.2.0 as a local dotnet tool. The pre-commit hook now runs ./build.sh lint (moved from pre-push), which calls curb check with a .artifacts/curb.cache for incremental pre-commit runs. CI lint job calls curb check directly. Formatting changes land in a follow-up stacked PR. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- max_line_length 160 -> 140 - csharp_wrap_object_and_collection_initializer_style: wrap_if_long -> chop_if_long - add csharp_wrap_chained_method_calls = chop_if_long - add resharper_csharp_empty_block_style = together_same_line (Rider only) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
0.3.0 ships fixes for all three issues we filed: - #8 resharper_csharp_empty_block_style (now the default) - #10 csharp_wrap_chained_method_calls + max_chained_method_calls_on_line - #11 binary operator double-indent inside if () blocks New editorconfig keys: - csharp_wrap_chained_binary_expressions = chop_if_long - csharp_wrap_before_binary_opsign = true (explicit; was already default) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
3 tasks
theletterf
approved these changes
Aug 20, 2026
| else ["--include"] @ includeFiles | ||
| exec { run "dotnet" (["format"; "--verbosity"; "quiet"] @ includeArgs) } | ||
| let private format (_formatArgs: ParseResults<FormatArgs>) = | ||
| exec { run "dotnet" ["curb"; "format"; "."] } |
There was a problem hiding this comment.
FormatArgs.Include and LintArgs.Include are still parsed by the CLI, but this change now ignores both and always runs against ..
That creates a silent behavior change: ./build.sh format <files> / ./build.sh lint <files> now process the whole repo instead of the requested subset.
Could we either:
- map include args to the equivalent
curbscoping options, or - remove/deprecate the include args and update
build/CommandLine.fsusage text in the same PR so callers don’t get a no-op argument?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
We've been using
dotnet formatfor C# formatting. It works, but it's slow enough that we had to run it on pre-push instead of pre-commit — nobody wants to wait 46 seconds every time they save a commit. That means formatting feedback came late, and the friction was real.curb fixes this. It's a new C# formatting tool that reads your existing
.editorconfig— both standard .NET keys (dotnet_*, IDE0055) and ReSharper keys (resharper_*) — and formats without loading the MSBuild workspace. No project restore, no Roslyn workspace hydration. Here's what it clocked on our repo (1 201 files):dotnet curb format .dotnet curb check .dotnet format whitespacedotnet format(full)Fast enough to run on every commit. And in practice the pre-commit warmup cost is near zero — by the time you commit,
dotnet buildhas already run curb in Debug mode and written a cache. The check pass on commit burns through that cache rather than rescanning everything.What changed
The pre-commit hook now lints on every commit, not just on push. curb's incremental cache (
.artifacts/curb.cache) makes the check fast enough that there's no reason to defer it.CI calls
dotnet curb check .directly — no F# build wrapper overhead.The MSBuild integration means
dotnet buildin Debug mode auto-reformats any file that's out of style before the compiler sees it. In CI (Release mode) it errors instead of rewrites, which is what you want. You don't have to think about formatting — by the time compilation runs, style is already applied..editorconfigtightened up now that running the formatter is cheap:chop_if_longchop_if_longchop_if_long&& xnotx &&curb cleanup— if a build fails on diagnostics curb handles natively (unused usings, redundant modifiers, etc.), runcurb cleanupto apply those fixes in ~15ms from the SARIF the last build already wrote, no workspace load. Add--forwardto pass anything it can't handle todotnet format style.This PR is the toolchain only
The codebase has not been reformatted yet — that's #3905, stacked on this one. CI lint will be red here; it goes green once the formatting sweep lands.
Test plan
dotnet buildauto-reformats a deliberately mis-formatted file in Debug mode./build.sh lintcatches violations and exits non-zerodotnet curb format .clears all violations.cs/.fschanges (moved from pre-push)