Skip to content

fix: share tool templates across target frameworks - #11144

Merged
vicancy merged 3 commits into
dotnet:mainfrom
vicancy:fix-tool-template-deduplication
Sep 18, 2026
Merged

vicancy merged 3 commits into
dotnet:mainfrom
vicancy:fix-tool-template-deduplication

Conversation

@vicancy

@vicancy vicancy commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Restore the existing shared-template layout for the multi-target .NET tool. The release currently packs templates three times, once under each of tools/net8.0/any, tools/net9.0/any, and tools/net10.0/any.

  • Collect templates from the real publish directory, remove the framework-specific package entries by normalized source path, and add one shared templates/ directory using the first target framework.
  • Enable Docfx.DotnetToolMode while packing without incorrectly excluding the SDK's internal publish phase.
  • Regenerate the runtime configuration when alternating pack and publish, including --no-build, so installed tools use shared templates and normal/self-contained publish outputs continue using adjacent templates.
  • Add a real package regression script and wire it into the existing Windows/macOS/Linux CI jobs. It checks the archive layout and all three runtime configurations, installs the package for .NET 8/9/10 into isolated directories from a local-only feed, verifies every exported template against the built assets, and generates HTML and PDF. It also verifies a normal publish output after the pack/publish/no-build cycle.

No framework support, PDF functionality, source maps, dependencies, release tags, or signing behavior are removed or changed. This affects future packing, not already-published packages.

Root cause

The old PackagePath.StartsWith("tools/<tfm>/any/templates/") condition does not match SDK 10's split destination metadata (PackagePath = tools/<tfm>/any/, with the remaining path in RecursiveDir). Also, SDK 10 sets both _IsPacking and _IsPublishing during tool packing, so the old !_IsPublishing condition suppresses the shared-template runtime switch.

The fix does not depend on that destination-metadata shape. It identifies the actual template source files instead.

Measured package size

Same commit, generated templates, dependencies, version and local unsigned packing process:

Before After
Package bytes 94,713,551 74,252,897
Package MiB 90.33 70.81
Framework-specific template entries 1,350 0
Shared template files 0 450

Reduction: 21.6%. All 146 template source maps are retained once instead of three times. These are comparable local unsigned packages, not a claim that the final signed release will have exactly the same size.

Validation

  • New checks fail on the baseline package: no shared templates, three duplicate directories, and missing runtime switches for all three frameworks.
  • An additional publish -> pack --no-build check reproduced stale runtime configuration before the final fix and passes afterward.
  • Windows, SDK 10.0.401: actual installed .NET 8 and .NET 10 tools pass version, template list/export, all 450 exported-file hash checks, HTML content/assets, and PDF generation with warnings treated as errors.
  • Framework-dependent and actual self-contained win-x64 publish outputs pass the same template/HTML/PDF checks without tool-mode leakage.
  • All three target frameworks build; local .NET 9 execution is unavailable because that runtime is not installed. The added CI test runs all three frameworks on each existing OS job.
  • Existing docfx.Tests: 84 pass; 32 schema cases fail on an unchanged checkout-name assumption (PathHelper requires a directory named docfx or docfx.sln, while this isolated checkout has another name and the repo uses docfx.slnx). Two representative cases reproduce with the production project restored to unmodified main. This unrelated helper is not changed.
  • PowerShell syntax, CI YAML parsing, project formatting, and diff checks passed. Dependency restores used the approved feeds.

CI package metrics

Each distribution-test step now writes a GitHub Actions job summary and console table containing the actual package frameworks, template directories/files, remaining framework-local entries, duplicate file copies avoided, compressed/expanded shared-template size, and actual package size. Estimated duplicate data avoided is explicitly labeled and excludes ZIP entry overhead; it is not presented as a separately built before/after measurement.

vicancy and others added 3 commits September 18, 2026 14:40
Match packed templates by source path rather than SDK-dependent destination metadata. Refresh the shared-template runtime setting across pack, publish, and no-build transitions. Verify real package layout and installed template/HTML/PDF workflows in the three-platform CI matrix.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: bf666f99-8d30-4763-878d-b566c0ac2f2d
Report package-derived template directories, files, framework copies avoided, compressed and expanded sizes, and actual package size in the console and GitHub job summary. Label avoided-byte estimates separately from measured before/after package sizes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: bf666f99-8d30-4763-878d-b566c0ac2f2d
Keep package regression commands and sharing metrics in the PR description and test script. Retain only the current .NET SDK prerequisite update in the README.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: bf666f99-8d30-4763-878d-b566c0ac2f2d
@vicancy
vicancy merged commit c5bf110 into dotnet:main Sep 18, 2026
9 checks passed
@vicancy
vicancy deleted the fix-tool-template-deduplication branch September 18, 2026 06:15
This was referenced Sep 23, 2026
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.

2 participants