Skip to content

Add item-based AggregateConfigInput support, XML handler, and .NET 10 - #99

Open
richardsondev wants to merge 7 commits into
mainfrom
jorichar/item-based
Open

richardsondev wants to merge 7 commits into
mainfrom
jorichar/item-based

Conversation

@richardsondev

@richardsondev richardsondev commented Sep 13, 2026 •

Copy link
Copy Markdown
Owner

Summary

Adds an item-based way to use the package, modelled on Azure.Bicep.MSBuild: declare <AggregateConfigInput> items and the package's own AggregateConfigCompile target aggregates them during the build, with no custom target required. The legacy direct task invocation keeps working unchanged.

Alongside that, this PR adds an XML file handler, moves file writes to async, and brings the repository to the .NET 10 SDK.

Item-based configuration

<ItemGroup>
  <AggregateConfigInput Include="configs\*.yml"
                        OutputFile="$(IntermediateOutputPath)aggregated\config.json"
                        OutputType="Json"
                        AddSourceProperty="true" />
  <EmbeddedResource Include="$(IntermediateOutputPath)aggregated\config.json" />
</ItemGroup>
  • build/ and buildMultiTargeting/ props and targets are shipped in the package. The props file registers the task and the AggregateConfigInput build action.
  • AggregateConfigCompile runs before PrepareForBuild by default so generated files exist before resources are embedded. AggregateConfigCompileBeforeTargets, AggregateConfigCompileAfterTargets and AggregateConfigCompileDependsOn control the timing.
  • The target batches on OutputFile and uses Inputs/Outputs for incremental builds. Missing OutputType defaults to Json; missing OutputFile defaults to $(AggregateConfigOutputPath)%(Filename).json.
  • Multi-targeting projects run the target once per target framework; the outer build is skipped.

XML support

  • FileType.Xml reads and writes .xml. Root children become properties, attributes become @name, text next to attributes becomes #text, and repeated elements become arrays. JSON arrays are written as a wrapper element with one child per item.
  • Output uses a UTF-8 declaration and platform newlines.
  • FileType.Yml is added with Yaml kept as an alias.

Other changes

  • IFileSystem.WriteAllTextAsync replaces the synchronous write and the unused read helpers; every handler returns a Task from WriteOutput.
  • Tests and CI target the .NET 10 SDK. The build and integration workflows install the 8.0, 9.0 and 10.0 SDKs so the multi-targeting test project builds.
  • New PackageStructureTests build a single-target and a multi-target project against the freshly packed package, verifying both package layouts, item-based aggregation and the legacy invocation. The integration project also embeds three item-based outputs and checks them.
  • The format round-trip unit test now actually runs: its data source previously produced no cases because enum aliases made every permutation impossible.
  • README and a new migration guide document the item-based approach, metadata defaults and the XML mapping. An example project with sample configs lives in examples/.

Notes for reviewers

  • The InputDirectory semantics are unchanged: for item-based inputs the task merges every file of InputType in the directory that contains the items. Items sharing an OutputFile should live in the same directory.
  • PackageStructureTests need the freshly packed package. Locally: dotnet build src/Task -c Release -p:Version=0.0.1-local, then run dotnet test test/dirs.proj -c Release -p:Version=0.0.1-local -p:UseLocalPackageVersion=true with RestoreAdditionalProjectSources pointing at src/Task/bin/Release.
  • Moving the test projects to net10.0 should also unblock the Dependabot bump in Bump the nuget-dependencies group with 18 updates #98, which fails because Microsoft.Build 18.x no longer supports net9.0 test hosts.

Relates to #17 (sample projects), #21 (incremental output for the item-based path) and #33 (XML is a first step toward app.config support).

Test plan

  • dotnet test src/dirs.proj -c Release -warnaserror: 70 unit tests pass
  • dotnet test test/dirs.proj -c Release -warnaserror -p:UseLocalPackageVersion=true against a freshly packed package: 15 integration tests pass, including the single-target and multi-target package builds
  • CI green on Windows, Linux and macOS

Bump global.json to the 10.0.100 SDK, target net10.0 in the unit test
project, and install the 8.0, 9.0 and 10.0 SDKs in the build and
integration workflows so multi-targeting test projects can build.
The Pages workflow no longer requests a preview SDK.
IFileSystem now exposes WriteAllTextAsync and drops the unused read
helpers; every file handler returns a Task from WriteOutput.

A new XmlFileHandler maps XML to the JSON intermediate form: root
children become properties, attributes become @name, text next to
attributes becomes #text, and repeated elements become arrays. JSON
arrays are written back as a wrapper element with one child per item.
Output is written with a UTF-8 declaration and platform newlines.

FileType gains Xml, and Yml with Yaml kept as an alias. The unit test
data source for format round trips now deduplicates enum aliases and
only uses XML as a starting format, since XML carries no types.
Ship build/ and buildMultiTargeting/ props and targets in the package.
The props file registers the task and the AggregateConfigInput build
action; the targets file adds an AggregateConfigCompile target that runs
before PrepareForBuild by default, batches items by OutputFile, and
supports incremental builds through Inputs and Outputs. Missing
OutputType and OutputFile metadata default to Json and
$(AggregateConfigOutputPath)%(Filename).json. The target is skipped in
the outer build of multi-targeting projects.
The integration project now declares AggregateConfigInput items that are
embedded as resources and verified by EmbeddedResourceTests.
PackageStructureTests builds two standalone projects, one single-target
and one multi-target, against the freshly packed package to verify the
build/ and buildMultiTargeting/ layouts, item-based aggregation, and the
legacy direct task invocation. The package version reaches those
projects through assembly metadata set when UseLocalPackageVersion is
enabled. The explicit System.Text.Json reference is dropped because the
.NET 10 SDK prunes it, and the TestProjects folder is excluded from the
integration project's default items.
Describe the AggregateConfigInput item approach, its properties and
metadata defaults, the PrepareForBuild default timing, and the XML
mapping in the README. Add a migration guide to the docs site and an
example project with sample configuration files.
The example is a standalone project with its own PackageReference
version, so it must not inherit the repository's Directory.Packages.props
or restore fails with NU1008.
The Ubuntu and Windows integration jobs hung after the test host started.
The child dotnet build now disables MSBuild node reuse and the shared
compiler server so it cannot attach to processes owned by the outer test
run, reads stdout and stderr asynchronously so neither pipe can block,
and is killed with its output after four minutes instead of stalling the
job until the workflow timeout.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant