Contributing
Contributions are very welcome! Whether it is a bug fix, a new feature, improved documentation, or just a question — please feel free to open an issue or pull request.
Getting the Code
git clone https://github.com/psachmann/dotnet-query.git
cd dotnet-query
Setting Up Your Dev Environment
Option A: Nix (recommended for reproducibility)
A Nix flake is provided with all required tools pinned to exact versions. With Nix and direnv installed, simply run:
direnv allow
The environment activates automatically whenever you enter the directory.
Option B: Manual
You need:
| Tool | Version |
|---|---|
| .NET SDK | 10.0 (see global.json) |
| CSharpier | 1.3.0 (installed as a local dotnet tool) |
After cloning, restore the local tools and packages:
dotnet tool restore
dotnet restore
Git Hooks
The repo ships husky hook definitions in .husky/, but no
project wires them up automatically — install them once per clone:
dotnet husky install
This adds a pre-commit hook that runs dotnet csharpier format on staged files, and a pre-push hook
that runs the full test suite (dotnet test -c Release). Both mirror checks CI also runs, so the
hooks just let you catch a formatting or test failure before pushing instead of after.
Common Commands
# Build
dotnet build
# Run all tests
dotnet test
# Run tests with coverage
dotnet test --configuration Release -- --coverage --coverage-output-format cobertura
# Check formatting
dotnet csharpier check .
# Fix formatting
dotnet csharpier format .
# Build the documentation site
dotnet docfx docs/docfx.json
Code Style
The project uses CSharpier for formatting, enforced as a CI gate and as a husky pre-commit hook (see Git Hooks below). Run dotnet csharpier format . locally before pushing to avoid the CI failing on formatting.
There is no extensive style guide beyond what CSharpier enforces — just try to follow the patterns already present in the codebase.
Build Gates
Four gates guard the shipping surface under src/ (tests and samples are unaffected). Any of them can
turn a change that builds locally into a Release-build failure, so it's worth knowing what each one is
before your PR trips it:
Public API tracking — every
src/project (except DevTools) lists its entire public surface inPublicAPI.Shipped.txt/PublicAPI.Unshipped.txt. Adding, removing, or changing a public member fails the Release build (RS0016/RS0017) until you add or remove the line. Apply the IDE's "Add to public API" code fix, or run:dotnet format analyzers DotNetQuery.slnx --diagnostics RS0016 --severity warnThis can't touch
.razorfiles —<Suspense>-style component members go intosrc/DotNetQuery.Blazor/PublicAPI.Unshipped.txtby hand, using the exact line theRS0016message gives you.Package validation —
dotnet packdiffs each assembly against the last stable release and fails on an unintentional breaking change. It only runs onpack, notbuild, so rundotnet pack -c Releaselocally if your change touches a public member. An intentional break needs a suppression file, not a weakened gate:dotnet pack -c Release -p:ApiCompatGenerateSuppressionFile=trueBanned symbols (
src/BannedSymbols.txt) — bans ambient time (DateTime.Now/.UtcNow, etc.) and blocking waits (Thread.Sleep,Task.Delay) asRS0030. All time insrc/must flow through the injectedISchedulerso tests can drive it withTestScheduler— this gate is what catches a strayDateTime.UtcNowbefore it ships. Test code is exempt.Trim / AOT analyzers — every
src/project except DevTools claims trim and AOT compatibility. A construct that can't be statically analyzed for trimming fails the Release build rather than surfacing later as a runtime failure in a consumer's trimmed or AOT-published app.
Making Changes
- Fork the repository and create a branch from
main. - Write tests for your change. All new behavior should be covered by tests.
- Run the full test suite to make sure nothing is broken:
dotnet test. - Check formatting:
dotnet csharpier check . - Open a pull request against
mainwith a clear description of what you changed and why.
Adding a New Feature
If you are thinking about a larger feature or a change to the public API, please open an issue first to discuss it. That saves everyone time and avoids the frustration of a PR being declined after significant work.
Fixing a Bug
- Open an issue describing the bug (if one does not exist already).
- Add a failing test that reproduces the bug.
- Fix the bug so the test passes.
- Open a pull request linking to the issue.
Making a Breaking Change
Breaking changes only ship in a major release, so please open an issue first. Once one is agreed, document it in the migration guide in the same pull request — you know the why and the fix better than anyone will at release time.
The guide is docs/doc/migrating-to-v<N>.md, where <N> is the upcoming major (currently migrating-to-v3.md). Your PR owes it an entry if it:
- adds a suppression to a
CompatibilitySuppressions.xmlor a*REMOVED*line to aPublicAPI.Unshipped.txt(see Build Gates), or - changes behaviour or telemetry (names, units, tags) in a way existing code still compiles against. No gate catches these, which is exactly why they need writing down.
Each entry is a row in the "At a Glance" table plus a section under "Breaking Changes" with what changed, the error or symptom a consumer sees, a Why:, and a How to migrate: — with before/after code where it applies. migrating-to-v2.md shows the tone and depth to aim for.
If yours is the first break of a new major, create the file and add it to docs/doc/toc.yml above the previous guide.
There is no changelog file to update: release notes are generated by GitHub from pull request titles, so a clear PR title is all they need.
Which section of the notes a PR lands in is decided by its label, configured in
.github/release.yml: breaking-change,
enhancement and bug get their own sections, anything else falls under "Other Changes", and Dependabot
PRs (label dependencies) are left out. Labels are read when the release is published, so they can still be
added to merged PRs afterwards.
Improving Documentation
Documentation lives in the docs/doc/ directory as Markdown files. Changes to documentation are just as valuable as code changes — please feel free to open PRs for typos, unclear explanations, missing examples, or anything else.
Running the Documentation Site Locally
DocFX is already restored as a local tool by dotnet tool restore (see Setting Up Your Dev
Environment).
# Build and serve locally
dotnet docfx docs/docfx.json --serve
Then open http://localhost:8080 in your browser.
CI / CD
The build pipeline runs on every push and pull request to main:
- Restore tools and packages
- CSharpier format check
- Release build (warnings are treated as errors in Release mode)
- Tests with code coverage (Cobertura format)
- Coverage upload to Codecov
Pull requests must pass all CI checks before merging.
Reporting Issues
Found a bug? Have a question? Please open an issue with:
- a clear description of the problem or question,
- a minimal reproduction (if it is a bug),
- the .NET version and platform you are using.
License
By contributing to DotNet Query, you agree that your contributions will be licensed under the MIT License.