MSBuild SDK
DotnetAffected.Tasks is an MSBuild project SDK that computes the affected projects during evaluation and hands them
to Microsoft.Build.Traversal for execution. There
is no CLI to install and no intermediate affected.proj — you run dotnet build against one file and only the
affected projects are built.
Set it up
Section titled “Set it up”Create a project file at the root of the Git repository. The name is yours to choose; ci.props is the
convention.
<Project Sdk="DotnetAffected.Tasks/7.0.0;Microsoft.Build.Traversal/4.1.82"></Project>Then build, test or clean through it:
dotnet build ./ci.propsdotnet test ./ci.propsInstead of repeating versions in every file, pin them in global.json:
{ "msbuild-sdks": { "DotnetAffected.Tasks": "7.0.0", "Microsoft.Build.Traversal": "4.1.82" }}<Project Sdk="DotnetAffected.Tasks;Microsoft.Build.Traversal"></Project>What it does during a build
Section titled “What it does during a build”The SDK adds DotnetAffectedCheck as an initial target, so it runs before anything else. The target computes the
changed and affected projects, clears any existing ProjectReference items and replaces them with the result. From
there the Traversal SDK builds exactly those projects.
Two consequences follow:
- Anything that feeds the check — the baseline, assumed changes, filter classes — must be in place before
DotnetAffectedCheckruns: at evaluation time, or in a target withBeforeTargets="DotnetAffectedCheck". - Anything that post-processes the result belongs in a target with
AfterTargets="DotnetAffectedCheck".
<Project Sdk="DotnetAffected.Tasks;Microsoft.Build.Traversal"> <Target Name="_PrintAffected" AfterTargets="DotnetAffectedCheck"> <Message Text="Found $(DotnetAffectedProjectCount) projects:" Importance="high" /> <Message Text=" >> %(ProjectReference.Identity)" Importance="high" /> </Target></Project>Choosing the comparison
Section titled “Choosing the comparison”By default the comparison is HEAD against the working tree, exactly like the CLI. Name the baseline, and choose what
the working tree contributes:
<Project Sdk="DotnetAffected.Tasks;Microsoft.Build.Traversal"> <PropertyGroup> <DotnetAffectedFromRef>origin/main</DotnetAffectedFromRef> <!-- All (default), Staged, or None --> <DotnetAffectedUncommitted>None</DotnetAffectedUncommitted> </PropertyGroup></Project>There is no property for the other end of the comparison: projects are discovered and evaluated from the working tree,
so that is always where it ends. DotnetAffectedToRef still exists, warns when used, and will be removed in v8.
Or bypass Git entirely and assume changes, by name or by glob:
<Project Sdk="DotnetAffected.Tasks;Microsoft.Build.Traversal"> <ItemGroup> <!-- Every csproj matching the pattern --> <DotnetAffectedAssumeChanges Include="$(MSBuildThisFileDirectory)**/project-*.csproj" /> <!-- Or by project name — this throws if no project matches --> <DotnetAffectedAssumeChanges Include="project3" /> </ItemGroup></Project>See the SDK reference for every input and output, and Filtering by project properties for narrowing the result using each project’s own evaluated properties.