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
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ All notable changes to DotNetDevMCP are documented here. The format follows
that forwards the original `Origin`, or a non-browser client that happens to set one. `--http` still has no
authentication or TLS and still shouldn't be exposed beyond localhost.

### Added
- `dotnet_test_affected`'s project fallback now follows NuGet package references, not just `ProjectReference`s: when a
test project's restored `obj/project.assets.json` references another solution project's package id (a literal
`<PackageId>`, one from the nearest `Directory.Build.props`, or the assembly name), that test project is selected
even with no `ProjectReference` between them. A change to `Directory.Packages.props` is narrowed, via the same
assets data, to the test projects that use the package ids whose version actually moved (diffed against git) -
walking from EVERY solution project whose restored assets reference a changed id, not just test projects', so a
`PrivateAssets="all"` package (an analyzer or source generator) a source project consumes directly is still
tracked to the test projects that reference that source project - but only when `Directory.Packages.props` is the
*only* changed file, only `Version` attributes actually changed (any other edit to the file, even alongside a
version bump, is treated as "beyond package versions" and not narrowed), and every solution project has been
restored; helper libraries with no test method are never selected, and a narrowed set that turns out to cover
every runnable test project runs the whole solution in one invocation instead. Any other case runs the whole
solution, with a note explaining why (git unavailable, the file doesn't parse, something beyond package versions
changed, an unrestored project, or no restored project uses those ids). Test projects with no
`obj/project.assets.json` (not restored) are called out in the note when the run falls back to whole test projects.

### Fixed
- `dotnet_test_affected`: a changed `.txt` or image inside a project folder (test data such as `TestData/expected.txt` or
Verify's `*.verified.txt`) was ignored, so nothing ran. It now selects that project's tests. `.md` files, and
documentation outside every project, are still ignored; a project at the solution root doesn't make docs count.

## [0.3.3] - 2026-09-24

Prompted by an external evaluation; each claim was checked against the code first.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Measured with BenchmarkDotNet on an i7-10750H, .NET 10.0.9. The orchestration be

After an edit, the agent usually reruns the whole suite. `dotnet_test_affected` asks Roslyn instead: take the symbols declared in the changed files, follow references (up to `maxDepth` hops, default 8) until you land in a method with `[Fact]`, `[Theory]`, `[Test]`, `[TestCase]` or `[TestMethod]`, then run exactly those. Changed files default to the git working tree, or `gitBase: "main"` for a branch. `dryRun: true` lists the tests without running them; `framework: "net10.0"` runs one target framework of multi-targeted test projects.

The walk has a time budget (`maxSelectionSeconds`, default 10). A change to code that everything depends on reaches too much to trace cheaply; then the test projects that reference the changed projects run instead (the whole solution if that's all of them), and the response says so (`selectionComplete: false`, `ranScope`). The same happens when the selection is more than 20% of all tests (`maxSelectedFraction`), where a filtered run is no faster. Changed files the walk can't trace (a `.csproj`, `.razor`, `appsettings.json`, a deleted file) switch to the same project fallback and are listed in `untracedFiles`; a changed `Directory.Build.props`, `global.json` or `.editorconfig` runs the whole solution. You never get a silently partial selection. Runs are killed after `timeoutSeconds` (default 600) so a hanging test cannot hang the agent; the response names the test modules that never finished. `maxDepth: 3` narrows more changes but misses more tests. Works with VSTest and with Microsoft.Testing.Platform (`"test": { "runner": "Microsoft.Testing.Platform" }` in global.json).
The walk has a time budget (`maxSelectionSeconds`, default 10). A change to code that everything depends on reaches too much to trace cheaply; then the test projects that reference the changed projects run instead (the whole solution if that's all of them), and the response says so (`selectionComplete: false`, `ranScope`). The same happens when the selection is more than 20% of all tests (`maxSelectedFraction`), where a filtered run is no faster. Changed files the walk can't trace (a `.csproj`, `.razor`, `appsettings.json`, a deleted file) switch to the same project fallback and are listed in `untracedFiles`; a changed `Directory.Build.props`, `global.json` or `.editorconfig` runs the whole solution. You never get a silently partial selection. Runs are killed after `timeoutSeconds` (default 600) so a hanging test cannot hang the agent; the response names the test modules that never finished. `maxDepth: 3` narrows more changes but misses more tests. Works with VSTest and with Microsoft.Testing.Platform (`"test": { "runner": "Microsoft.Testing.Platform" }` in global.json). The project fallback also follows restored NuGet package references (a test project whose `obj/project.assets.json` references another solution project's package id, with no `ProjectReference` between them, is still selected). A change to `Directory.Packages.props` is narrowed to the test projects that actually use the package ids whose version moved only when it is the *only* changed file (documentation outside every project aside), only the `Version` attributes actually changed (not a `Condition`, a `GlobalPackageReference`, or any other edit riding along), and every solution project has been restored; any other change to that file, a change alongside another file, or an unrestored project anywhere in the solution runs the whole solution instead, with a note explaining which of those applied.

On this repository, editing `ConcurrentExecutor.cs` selects 22 of 44 tests (the `ConcurrentExecutorTests` plus the `OrchestrationServiceTests` that reach it through `OrchestrationService`). Measured through the MCP tool, build included, i7-10750H:

Expand Down Expand Up @@ -195,7 +195,7 @@ Built on the official [MCP C# SDK](https://github.com/modelcontextprotocol/cshar

0.3.3. The Roslyn tools are mature (they come from SharpTools). Testing, build, git and orchestration are newer and have been exercised on this repository and a few others; expect rough edges on unusual project layouts. Issues and PRs welcome, see [CONTRIBUTING](https://github.com/csa7mdm/DotNetDevMCP/blob/main/CONTRIBUTING.md).

Known gaps: `dotnet_test_affected` follows C# references only (no reflection, no DI-by-convention, no string-keyed lookups), so a change reached only through those paths will not select the test; use `dryRun` to check what it picks. Calls through an interface or base class are followed. The project fallback follows `ProjectReference`s only: a test project that uses the changed code through a NuGet package is not found. Builds and tests are not sandboxed (see Security). Tests that hang instead of failing are only caught by a run that finishes. Test attribute detection covers xUnit, NUnit and MSTest by attribute name. Past the command-line length limit the filter widens from methods to classes, then to the whole project (more tests, never fewer).
Known gaps: `dotnet_test_affected` follows C# references only (no reflection, no DI-by-convention, no string-keyed lookups), so a change reached only through those paths will not select the test; use `dryRun` to check what it picks. Calls through an interface or base class are followed. The project fallback follows `ProjectReference`s and NuGet package references: package references are now followed when the test project has been restored; cross-repo consumers are not. Builds and tests are not sandboxed (see Security). Tests that hang instead of failing are only caught by a run that finishes. Test attribute detection covers xUnit, NUnit and MSTest by attribute name. Past the command-line length limit the filter widens from methods to classes, then to the whole project (more tests, never fewer).

## Credits and license

Expand Down
Loading
Loading