Skip to content

JerrettDavis/JD.MSBuild.Fluent

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

32 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

JD.MSBuild.Fluent

A strongly-typed, fluent DSL for authoring MSBuild packages in C#

NuGet License CI codecov Documentation

Author MSBuild .props, .targets, and SDK assets using a strongly-typed fluent API in C#, then automatically generate 100% standard MSBuild XML during build. No more hand-editing XML - write refactorable, testable, type-safe C# code instead.

πŸ“š Documentation

View Complete Documentation

✨ Features

  • 🎯 Strongly-typed fluent API - IntelliSense, refactoring, compile-time validation
  • πŸ”„ Automatic build integration - Generate MSBuild assets during dotnet build, no CLI required
  • πŸ“¦ Full NuGet layout support - build/, buildTransitive/, and Sdk/ folders
  • πŸ”§ XML scaffolding - Convert existing XML to fluent code with jdmsbuild scaffold
  • βœ… Production-tested - Validated against real-world MSBuild packages
  • πŸ“ Deterministic output - Consistent XML generation for meaningful diffs

Quick Start

1. Install the package

<PackageReference Include="JD.MSBuild.Fluent" Version="*" />

2. Define your MSBuild assets in C#

using JD.MSBuild.Fluent;
using JD.MSBuild.Fluent.Fluent;

namespace MySdk;

public static class DefinitionFactory
{
  public static PackageDefinition Create() => Package.Define("MySdk")
    .Props(p => p
      .Property("MySdkEnabled", "true")
      .Property("MySdkVersion", "1.0.0"))
    .Targets(t => t
      .Target("MySdk_Hello", target => target
        .BeforeTargets("Build")
        .Condition("'$(MySdkEnabled)' == 'true'")
        .Message("Hello from MySdk v$(MySdkVersion)!", "High")))
    .Pack(o => { 
      o.BuildTransitive = true; 
      o.EmitSdk = true; 
    })
    .Build();
}

3. Build your project

MSBuild assets are automatically generated during build and packaged correctly:

  • βœ… build/MySdk.props
  • βœ… build/MySdk.targets
  • βœ… buildTransitive/MySdk.props and .targets (if enabled)
  • βœ… Sdk/MySdk/Sdk.props and Sdk.targets (if SDK enabled)

No CLI required! Just build and pack:

dotnet build
dotnet pack

Optional: Configure generation

<PropertyGroup>
  <!-- Enable/disable generation (default: true) -->
  <JDMSBuildFluentGenerateEnabled>true</JDMSBuildFluentGenerateEnabled>
  
  <!-- Specify factory type (default: auto-detect) -->
  <JDMSBuildFluentDefinitionType>MySdk.DefinitionFactory</JDMSBuildFluentDefinitionType>
  
  <!-- Output directory (default: obj/msbuild) -->
  <JDMSBuildFluentOutputDir>$(MSBuildProjectDirectory)\msbuild</JDMSBuildFluentOutputDir>
</PropertyGroup>

πŸ”„ Migrate from XML

Convert existing MSBuild XML files to fluent API:

# Install CLI tool
dotnet tool install -g JD.MSBuild.Fluent.Cli

# Scaffold from existing XML
jdmsbuild scaffold --xml MyPackage.targets --output DefinitionFactory.cs --package-id MyCompany.MyPackage

Before (XML):

<Project>
  <PropertyGroup>
    <MyPackageVersion>1.0.0</MyPackageVersion>
  </PropertyGroup>
  <Target Name="Hello" BeforeTargets="Build">
    <Message Text="Hello from MyPackage v$(MyPackageVersion)!" Importance="High" />
  </Target>
</Project>

After (Fluent C#):

public static PackageDefinition Create()
{
    return Package.Define("MyPackage")
        .Targets(t =>
        {
            t.PropertyGroup(null, group =>
            {
                group.Property("MyPackageVersion", "1.0.0");
            });
            t.Target("Hello", target =>
            {
                target.BeforeTargets("Build");
                target.Message("Hello from MyPackage v$(MyPackageVersion)!", "High");
            });
        })
        .Build();
}

Now you can refactor, test, and maintain your MSBuild logic like regular C# code!

🎯 Why JD.MSBuild.Fluent?

Problem: Hand-editing MSBuild XML is painful

  • ❌ No IntelliSense or type safety
  • ❌ No refactoring support
  • ❌ Hard to test and validate
  • ❌ Copy-paste leads to duplication
  • ❌ Difficult to review diffs

Solution: Write C# instead

  • βœ… Strongly-typed API with full IntelliSense
  • βœ… Refactoring support - rename, extract, move
  • βœ… Unit testable - validate logic before publishing
  • βœ… DRY principle - reuse patterns across targets
  • βœ… Better diffs - meaningful C# changes instead of XML noise
  • βœ… Automatic generation - integrated into build pipeline

πŸ“¦ CLI Tool (Optional)

The CLI is optional for advanced scenarios. Most users don't need it since generation happens automatically during build.

# Install globally
dotnet tool install -g JD.MSBuild.Fluent.Cli

# Generate assets manually
jdmsbuild generate --assembly path/to/MySdk.dll --type MySdk.DefinitionFactory --output msbuild

# Generate built-in example
jdmsbuild generate --example --output artifacts/msbuild

# Scaffold from XML
jdmsbuild scaffold --xml MyPackage.targets --output DefinitionFactory.cs

πŸ“ Output Layout

Generated files follow standard NuGet conventions:

build/
  MySdk.props          ← Applied to direct consumers
  MySdk.targets        ← Applied to direct consumers
buildTransitive/       ← (optional)
  MySdk.props          ← Applied transitively
  MySdk.targets        ← Applied transitively
Sdk/                   ← (optional)
  MySdk/
    Sdk.props          ← SDK-style project support
    Sdk.targets        ← SDK-style project support

πŸ§ͺ Samples

πŸ” Deterministic Output

The XML renderer produces deterministic, canonical output:

  • Consistent property ordering
  • Consistent item metadata ordering
  • Consistent task parameter ordering
  • Meaningful diffs across versions

🀝 Contributing

Contributions welcome! This project follows standard GitHub flow:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with tests
  4. Submit a pull request

πŸ“„ License

MIT License

πŸ”— Related Projects

About

A fluent DSL for building MSBuild props, targets, and SDKs

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages