Skip to content

Migrate Microsoft.TestPlatform.CLI from nuspec to MSBuild pack (final batch) - #16149

Merged
Jakub Jareš (nohwnd) merged 13 commits into
microsoft:mainfrom
azat-msft:migrate-nuspec-to-msbuild-pack-final-batch
Jun 24, 2026
Merged

Migrate Microsoft.TestPlatform.CLI from nuspec to MSBuild pack (final batch)#16149
Jakub Jareš (nohwnd) merged 13 commits into
microsoft:mainfrom
azat-msft:migrate-nuspec-to-msbuild-pack-final-batch

Conversation

@azat-msft

Copy link
Copy Markdown
Member

Summary

Completes the migration from hand-written .nuspec files to MSBuild pack (csproj-based
packaging), per #15650. This is the final batch: it migrates the last remaining package,
Microsoft.TestPlatform.CLI, which was explicitly deferred by the earlier batches
(#16125 simple packages, #16132 container packages) because it was the riskiest.

Note: this branch stacks on top of #16132, so the diff also contains the batch-2 container
packages (TranslationLayer, Internal.Uwp, NET.Test.Sdk, CodeCoverage, TestHost, TestPlatform,
Portable). The new work in this PR is the Microsoft.TestPlatform.CLI migration. If #16132
is merged first, only the CLI commit remains here.

What changed for Microsoft.TestPlatform.CLI

The project previously selected one of three hand-written nuspecs via <NuspecFile> conditions:

Variant When
Microsoft.TestPlatform.CLI.nuspec Windows, non source-build (full net10.0 layout + .NET Framework test hosts)
Microsoft.TestPlatform.CLI.sourcebuild.nuspec non-Windows / source-build, non-VMR (cross-platform $(NetCurrent) layout)
Microsoft.TestPlatform.CLI.sourcebuild.product.nuspec source-build, VMR (identical to the sourcebuild variant)

All three are replaced by csproj packaging:

  • Every <file src=".." target=".." /> element becomes a <None Pack="true" PackagePath=".."> item.
  • Because the package ships everything under contentFiles, each content item carries
    BuildAction=None / PackageCopyToOutput=true / PackageFlatten=false, so pack emits per-file
    <contentFiles> entries that are functionally equivalent to the original generic
    <contentFiles><files include="**/*.*" copyToOutput="true" flatten="false" buildAction="None" /></contentFiles>
    wildcard.
  • The Windows full content is gated on '$(DotNetBuildSourceOnly)' != 'true' and '$(OS)' == 'Windows_NT';
    the cross-platform $(NetCurrent) content (covering both identical sourcebuild nuspecs) is gated on
    '$(DotNetBuildSourceOnly)' == 'true' or '$(OS)' != 'Windows_NT'.
  • Container settings IncludeBuildOutput=false and SuppressDependenciesWhenPacking=true are used
    (the package ships no assembly of its own and has no NuGet dependencies).
  • The existing ProjectReference, PackageReference and CopyFiles staging logic is unchanged.

The three .nuspec files are deleted.

Validation

A clean build.cmd -c Release -pack produces a CLI package whose file list is byte-for-byte
identical
to the pre-migration package (483 entries), with no eng/expected-*.json drift.
The generated nuspec metadata matches the previous one; the only differences are the per-file
contentFiles entries (vs. the single wildcard, functionally equivalent) and a benign auto-added
<frameworkAssemblies> entry that is not part of the file-list oracle. The full Release build's
nupkg-file-count and DLL-target-framework verification pipeline passes.

Known limitation

The sourcebuild / sourcebuild.product paths only execute under -DotNetBuildSourceOnly / VMR
builds and cannot be exercised by a local Windows build. They are translated faithfully but
validated by inspection only — worth confirming on a source-build / VMR CI leg before merge.

Closes #15650 (CLI follow-up).

Remove the hand-crafted .nuspec file for
Microsoft.TestPlatform.VsTestConsole.TranslationLayer and use MSBuild pack
properties instead.

- Remove NuspecFile/NuspecBasePath/NuspecProperty items
- ObjectModel stays a real NuGet dependency; Common, CoreUtilities and
  CommunicationUtilities are marked PrivateAssets=all (bundled, not deps)
- Use TargetsForTfmSpecificContentInPackage to bundle Common and
  CommunicationUtilities DLLs plus satellite resources (incl. CoreUtilities
  resources) and the TranslationLayer XML doc into lib/<tfm>
- Add PackageReadmeFile and None items for README.md and ThirdPartyNotices.txt
- Delete Microsoft.TestPlatform.VsTestConsole.TranslationLayer.nuspec

Package contents verified identical to the previous nuspec output (175 files).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the hand-crafted .nuspec file for Microsoft.TestPlatform.Internal.Uwp
and use MSBuild pack properties instead.

- Remove NuspecFile/NuspecBasePath properties
- Set IncludeBuildOutput=false (the package ships bundled DLLs, not its own
  Internal.Uwp assembly) and SuppressDependenciesWhenPacking=true (no deps)
- Mark both ProjectReferences PrivateAssets=all
- Add NoWarn=NU5128 (bundled-only package with an empty dependency group)
- Use TargetsForTfmSpecificContentInPackage to bundle ObjectModel,
  CoreUtilities, CrossPlatEngine, CommunicationUtilities, Utilities, Common and
  PlatformAbstractions DLLs plus ObjectModel and CoreUtilities satellite
  resources into lib/netstandard2.0
- Add PackageReadmeFile and None item for README.md
- Delete Microsoft.TestPlatform.Internal.Uwp.nuspec

Package contents verified identical to the previous nuspec output (39 files).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the hand-crafted .nuspec file for Microsoft.NET.Test.Sdk and use MSBuild
pack properties instead.

- Multi-target net8.0;net462 so pack emits the per-framework dependency groups
- Express dependencies via ProjectReferences to the sibling packable projects:
  net8.0 depends on TestHost + CodeCoverage, net462 on CodeCoverage only
- IncludeBuildOutput=false (build/targets-only package, ships no own assembly)
  and NoWarn=NU5128
- Ship the props/targets into build\<tfm> and buildMultiTargeting\<tfm> and the
  _._ lib stubs via Pack-enabled None items with explicit PackagePath
- Add PackageReadmeFile for README.md
- Delete Microsoft.NET.Test.Sdk.nuspec

Package file list verified identical to the previous nuspec output (26 files)
and the net8.0/net462 dependency groups match. The only difference is that the
old nuspec's empty native0.0 dependency group is no longer emitted: MSBuild pack
only generates dependency groups for real build target frameworks. This is
behaviorally equivalent because the group carried no dependencies and
lib/native/_._ still marks the package compatible with native test projects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the hand-crafted .nuspec file for Microsoft.CodeCoverage and use MSBuild
pack properties instead.

- IncludeBuildOutput=false (the package ships only build\ tooling and a bundled
  content tree, not its own assembly) and SuppressDependenciesWhenPacking=true
- Ship README.md, ThirdPartyNotices.txt (root + build\netstandard2.0) and the
  Microsoft.CodeCoverage props/targets via Pack-enabled None items
- Bundle the Microsoft.Internal.CodeCoverage content tree (code coverage tools,
  instrumentation engines and shims, pre-laid-out as build\ + lib\ + PACKAGE.md)
  at the package root via TargetsForTfmSpecificContentInPackage. This runs in the
  inner per-TFM build because the package path property is only defined there,
  gated to a single TFM so the content ships once, with PackagePath=%(RecursiveDir)
  preserving the folder structure
- NoWarn the package-analysis warnings that fire for a build\-only tooling package
- Delete Microsoft.CodeCoverage.nuspec

Package file list verified identical to the previous nuspec output (81 files).
The only difference is the dependency metadata: the old nuspec declared two empty
dependency groups (net462, net8.0); MSBuild pack with SuppressDependenciesWhenPacking
omits the <dependencies> element entirely. This is behaviorally equivalent because
the package has no NuGet dependencies and the old groups were empty.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the hand-crafted .nuspec file for Microsoft.TestPlatform.TestHost and use
MSBuild pack properties instead.

- IncludeBuildOutput=false (the package bundles the testhost runtime output, not
  its own TestHost assembly)
- ObjectModel is a real net8.0 dependency (conditioned to the .NET build so the
  net462 group stays empty, matching the old nuspec)
- testhost / testhost.x86 project references are kept to produce the bundled
  output but removed from the resolved dependency list (PrivateAssets is not
  honored for these exe references), so they do not leak as NuGet dependencies
- Bundle via TargetsForTfmSpecificContentInPackage (net8.0 inner build): platform
  assemblies + CommunicationUtilities/CrossPlatEngine/Common satellites into
  lib\net8.0, msdia140 natives into lib\net8.0\{x86,x64,arm64}, the testhost
  launchers into build\net8.0\{x64,x86} and the props/targets into build\net8.0
- Ship README.md, ThirdPartyNotices.txt and the lib\net462\_._ stub via Pack items
- Delete Microsoft.TestPlatform.TestHost.nuspec

Package contents and dependency groups verified identical to the previous nuspec
output (65 files; net8.0 -> ObjectModel, net462 empty).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the hand-written 535-line Microsoft.TestPlatform.nuspec with MSBuild
pack: the 487 <file> elements are translated to <None Pack=true> items that
map the same build outputs to the same package paths, producing a byte-identical
553-file layout (verified against the pre-change package).

- Remove NuspecFile/NuspecBasePath and the NuspecProperty ItemGroup
- IncludeBuildOutput=false (container project, ships no assembly of its own)
- SuppressDependenciesWhenPacking=true (package has no NuGet dependencies)
- Add PackageReadmeFile and explicit None items for README, LICENSE_VS.txt
  (PackageLicenseFullPath is not auto-packed) and ThirdPartyNotices.txt
- Clear the inherited MIT PackageLicenseExpression so the file license applies
- NoWarn NU5100/NU5109/NU5118/NU5128 (assemblies/content outside lib, no deps)
- Recursive ** globs reproduced with folder PackagePath (RecursiveDir preserved)
- Delete Microsoft.TestPlatform.nuspec

Pack now auto-adds a benign <frameworkAssemblies> entry
(System.Runtime.InteropServices.RuntimeInformation for net48/net481) that the
old nuspec omitted; it does not affect the packaged files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…d pack

Replace the hand-written 657-line Microsoft.TestPlatform.Portable.nuspec with
MSBuild pack: the 601 <file> elements are translated to <None Pack=true> items
that map the same build outputs to the same package paths, producing a
byte-identical 608-file layout (verified against the pre-change package).

- Remove NuspecFile/NuspecBasePath and the NuspecProperty ItemGroup
- IncludeBuildOutput=false, SuppressDependenciesWhenPacking=true (container, no deps)
- Add PackageReadmeFile and explicit None items for README and LICENSE_VS.txt
- Clear the inherited MIT PackageLicenseExpression so the file license applies
- NoWarn NU5100/NU5109/NU5118 (NU5128 was already present)
- Delete Microsoft.TestPlatform.Portable.nuspec

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a comment documenting the existing UTF-8 console-encoding behavior. This
is a comment-only change with no functional impact; it exists to exercise the
full CI pipeline (code-path checks are skipped for doc-only changes).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replaces the three hand-written nuspec variants
(Microsoft.TestPlatform.CLI.nuspec / .sourcebuild.nuspec / .sourcebuild.product.nuspec)
with csproj-based packaging, completing the migration started in microsoft#16125 / microsoft#16132
(issue microsoft#15650).

Each <file src target> element is translated to a <None Pack="true" PackagePath="...">
item. Because everything ships under contentFiles, every content item carries
BuildAction=None / PackageCopyToOutput=true / PackageFlatten=false so pack emits
per-file <contentFiles> entries that are functionally equivalent to the original
generic "**/*.*" copyToOutput/flatten/buildAction wildcard.

The Windows full content (net10.0 layout + net46x/net4x TestHostNetFramework hosts)
is gated on (!DotNetBuildSourceOnly and Windows); the cross-platform $(NetCurrent)
content (mirroring the two identical sourcebuild nuspecs) is gated on
(DotNetBuildSourceOnly or non-Windows). Container settings IncludeBuildOutput=false
and SuppressDependenciesWhenPacking=true are used (the package ships no assembly of
its own and has no NuGet dependencies). The existing ProjectReference, PackageReference
and CopyFiles staging logic is unchanged.

Validation: a clean `build.cmd -c Release -pack` produces a CLI package whose file
list is byte-for-byte identical to the pre-migration package (483 entries, no
eng/expected-*.json drift). The auto-added <frameworkAssemblies> entry is benign and
not part of the file-list oracle. The sourcebuild/VMR variants only execute under
-DotNetBuildSourceOnly / VMR builds and cannot be exercised by a local Windows build;
they are translated faithfully but validated only by inspection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 22, 2026 10:42
@azat-msft
Azat Mukhametshin (azat-msft) marked this pull request as draft June 22, 2026 10:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR completes the migration of Microsoft.TestPlatform.CLI (and the remaining container packages in this stacked branch) from hand-authored .nuspec files to SDK-style MSBuild packing, translating file lists into Pack="true" items and removing the legacy nuspec variants.

Changes:

  • Migrates Microsoft.TestPlatform.CLI packaging to csproj-authored contentFiles (with PackageCopyToOutput/PackageFlatten semantics) and deletes the three CLI .nuspec variants.
  • Migrates remaining container/tooling packages (e.g., Microsoft.CodeCoverage, Microsoft.NET.Test.Sdk, TestHost, Internal.Uwp, TranslationLayer) off .nuspec to MSBuild pack patterns.
  • Minor comment addition in vstest.console clarifying UTF-8 console encoding behavior behind a feature flag.

Reviewed changes

Copilot reviewed 17 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/vstest.console/Program.cs Adds an explanatory comment about UTF-8 console output being controlled by a feature flag.
src/package/Microsoft.TestPlatform/Microsoft.TestPlatform.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.TestPlatform.TestHost/Microsoft.TestPlatform.TestHost.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.TestPlatform.TestHost/Microsoft.TestPlatform.TestHost.csproj Switches TestHost package authoring to MSBuild pack, bundling runtime outputs via TargetsForTfmSpecificContentInPackage.
src/package/Microsoft.TestPlatform.Portable/Microsoft.TestPlatform.Portable.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.TestPlatform.Internal.Uwp/Microsoft.TestPlatform.Internal.Uwp.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.TestPlatform.Internal.Uwp/Microsoft.TestPlatform.Internal.Uwp.csproj Switches Internal.Uwp to MSBuild pack bundling (no build output, no dependencies).
src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.nuspec Removes legacy nuspec (Windows variant) as part of CLI migration.
src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.sourcebuild.nuspec Removes legacy nuspec (source-build variant) as part of CLI migration.
src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.sourcebuild.product.nuspec Removes legacy nuspec (VMR variant) as part of CLI migration.
src/package/Microsoft.NET.Test.Sdk/Microsoft.NET.Test.Sdk.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.NET.Test.Sdk/Microsoft.NET.Test.Sdk.csproj Switches the SDK package to MSBuild pack with explicit build/buildMultiTargeting assets and per-TFM deps.
src/package/Microsoft.CodeCoverage/Microsoft.CodeCoverage.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/package/Microsoft.CodeCoverage/Microsoft.CodeCoverage.csproj Switches CodeCoverage tooling package to MSBuild pack, including bundled Microsoft.Internal.CodeCoverage content.
src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.nuspec Removes legacy nuspec as part of MSBuild-pack migration.
src/Microsoft.TestPlatform.VsTestConsole.TranslationLayer/Microsoft.TestPlatform.VsTestConsole.TranslationLayer.csproj Switches TranslationLayer to MSBuild pack while bundling select assemblies/resources into the nupkg.

Comment thread src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj Outdated
Comment thread src/package/Microsoft.TestPlatform.CLI/Microsoft.TestPlatform.CLI.csproj Outdated
…time

The initial CLI migration used MSBuild item wildcards in static <ItemGroup>s
(`net462\System*.dll` for the Windows variant and the `**\*.resources.dll`
source-build resource globs). Static item wildcards are expanded during project
*evaluation*, which happens before the referenced projects' outputs have been
copied into this project's OutputPath. On a clean CI build the folders are empty
at that point, so the wildcards matched nothing and the Windows CLI package shipped
100 fewer files (383 instead of 483), failing verify-nupkgs.ps1. Locally the bug was
masked because a prior build had already populated the output folders.

Explicit (non-wildcard) <None> includes are literal items resolved at pack time, so:
- The Windows `net462\System*.dll` glob is expanded into explicit <None> items
  (matching the pattern already used by Microsoft.TestPlatform.csproj).
- The source-build localized satellite resources (which cannot be enumerated from a
  Windows build) are moved into a TargetsForTfmSpecificContentInPackage target, the
  repo's established pack-time content hook (see Microsoft.CodeCoverage.csproj). It is
  gated to $(NetCurrent) so the content is added exactly once, and %(RecursiveDir)
  preserves the language sub-folders.

Validated with a clean `build.cmd -c Release -pack` (artifacts/bin and
artifacts/packages deleted first to reproduce the CI state): the CLI package is again
byte-for-byte identical to the pre-migration package (483 entries) with no
eng/expected-*.json drift.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 22, 2026 15:37

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated 7 comments.

…-time TFM scoping

Addresses PR review feedback and a package-diff regression.

1. Casing fix (real bug). The runtime provider assembly is
   `Microsoft.TestPlatform.TestHostRuntimeProvider.dll` (capital `H`), but two `<None Include>`
   items copied a casing typo from the old nuspec's `src` attribute and used lowercase
   `TesthostRuntimeProvider.dll`. NuGet nuspec packing used the real on-disk name (capital `H`),
   whereas MSBuild pack ships the literal `Include` casing, so the new Windows package shipped
   the DLL as `Testhost...` and on case-sensitive filesystems (source-build / non-Windows) the
   literal include would not match the built file at all, dropping the DLL. Both occurrences
   (net10.0 Windows item and the $(NetCurrent) source-build item) are corrected to `TestHost`.
   The earlier byte-identical check missed this because PowerShell's Compare-Object is
   case-insensitive; an ordinal comparison now shows the package matches the pre-migration
   layout exactly (483 entries, zero case-sensitive diffs).

2. Pack-time resource globs (review comments, no code change needed). The reviewer flagged that
   the `$(OutputPath)**` resource globs in `_IncludeCliSourceBuildResources` could span other TFM
   subfolders. They cannot: the target runs via TargetsForTfmSpecificContentInPackage in the inner
   per-TFM build, where `$(OutputPath)` already resolves to the per-TFM directory
   (e.g. `...\Release\net11.0\`), so the globs only ever match that single TFM and `%(RecursiveDir)`
   is just the language folder (cs, de, ...). Verified empirically. Added a comment documenting this.

Validated with a clean `build.cmd -c Release -pack` (artifacts deleted first): build succeeds,
verification passes, no eng/expected-*.json drift, CLI package byte/layout-identical to the
pre-migration package under an ordinal (case-sensitive) comparison.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@azat-msft
Azat Mukhametshin (azat-msft) marked this pull request as ready for review June 23, 2026 14:25
Copilot AI review requested due to automatic review settings June 23, 2026 14:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 5 changed files in this pull request and generated no new comments.


internal static int Run(string[]? args, UiLanguageOverride uiLanguageOverride)
{
// Console output is switched to UTF-8 unless the feature flag opts out.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Console output is switched to UTF-8 unless the feature flag opts out.

Unrelated.

@nohwnd
Jakub Jareš (nohwnd) merged commit 4928f28 into microsoft:main Jun 24, 2026
30 of 35 checks passed
github-actions Bot added a commit to azat-msft/vstest that referenced this pull request Jun 24, 2026
… batch) (microsoft#16149)

* Migrate TranslationLayer package from nuspec to MSBuild pack

Remove the hand-crafted .nuspec file for
Microsoft.TestPlatform.VsTestConsole.TranslationLayer and use MSBuild pack
properties instead.

- Remove NuspecFile/NuspecBasePath/NuspecProperty items
- ObjectModel stays a real NuGet dependency; Common, CoreUtilities and
  CommunicationUtilities are marked PrivateAssets=all (bundled, not deps)
- Use TargetsForTfmSpecificContentInPackage to bundle Common and
  CommunicationUtilities DLLs plus satellite resources (incl. CoreUtilities
  resources) and the TranslationLayer XML doc into lib/<tfm>
- Add PackageReadmeFile and None items for README.md and ThirdPartyNotices.txt
- Delete Microsoft.TestPlatform.VsTestConsole.TranslationLayer.nuspec

Package contents verified identical to the previous nuspec output (175 files).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate Internal.Uwp package from nuspec to MSBuild pack

Remove the hand-crafted .nuspec file for Microsoft.TestPlatform.Internal.Uwp
and use MSBuild pack properties instead.

- Remove NuspecFile/NuspecBasePath properties
- Set IncludeBuildOutput=false (the package ships bundled DLLs, not its own
  Internal.Uwp assembly) and SuppressDependenciesWhenPacking=true (no deps)
- Mark both ProjectReferences PrivateAssets=all
- Add NoWarn=NU5128 (bundled-only package with an empty dependency group)
- Use TargetsForTfmSpecificContentInPackage to bundle ObjectModel,
  CoreUtilities, CrossPlatEngine, CommunicationUtilities, Utilities, Common and
  PlatformAbstractions DLLs plus ObjectModel and CoreUtilities satellite
  resources into lib/netstandard2.0
- Add PackageReadmeFile and None item for README.md
- Delete Microsoft.TestPlatform.Internal.Uwp.nuspec

Package contents verified identical to the previous nuspec output (39 files).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate NET.Test.Sdk package from nuspec to MSBuild pack

Remove the hand-crafted .nuspec file for Microsoft.NET.Test.Sdk and use MSBuild
pack properties instead.

- Multi-target net8.0;net462 so pack emits the per-framework dependency groups
- Express dependencies via ProjectReferences to the sibling packable projects:
  net8.0 depends on TestHost + CodeCoverage, net462 on CodeCoverage only
- IncludeBuildOutput=false (build/targets-only package, ships no own assembly)
  and NoWarn=NU5128
- Ship the props/targets into build\<tfm> and buildMultiTargeting\<tfm> and the
  _._ lib stubs via Pack-enabled None items with explicit PackagePath
- Add PackageReadmeFile for README.md
- Delete Microsoft.NET.Test.Sdk.nuspec

Package file list verified identical to the previous nuspec output (26 files)
and the net8.0/net462 dependency groups match. The only difference is that the
old nuspec's empty native0.0 dependency group is no longer emitted: MSBuild pack
only generates dependency groups for real build target frameworks. This is
behaviorally equivalent because the group carried no dependencies and
lib/native/_._ still marks the package compatible with native test projects.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate CodeCoverage package from nuspec to MSBuild pack

Remove the hand-crafted .nuspec file for Microsoft.CodeCoverage and use MSBuild
pack properties instead.

- IncludeBuildOutput=false (the package ships only build\ tooling and a bundled
  content tree, not its own assembly) and SuppressDependenciesWhenPacking=true
- Ship README.md, ThirdPartyNotices.txt (root + build\netstandard2.0) and the
  Microsoft.CodeCoverage props/targets via Pack-enabled None items
- Bundle the Microsoft.Internal.CodeCoverage content tree (code coverage tools,
  instrumentation engines and shims, pre-laid-out as build\ + lib\ + PACKAGE.md)
  at the package root via TargetsForTfmSpecificContentInPackage. This runs in the
  inner per-TFM build because the package path property is only defined there,
  gated to a single TFM so the content ships once, with PackagePath=%(RecursiveDir)
  preserving the folder structure
- NoWarn the package-analysis warnings that fire for a build\-only tooling package
- Delete Microsoft.CodeCoverage.nuspec

Package file list verified identical to the previous nuspec output (81 files).
The only difference is the dependency metadata: the old nuspec declared two empty
dependency groups (net462, net8.0); MSBuild pack with SuppressDependenciesWhenPacking
omits the <dependencies> element entirely. This is behaviorally equivalent because
the package has no NuGet dependencies and the old groups were empty.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate TestHost package from nuspec to MSBuild pack

Remove the hand-crafted .nuspec file for Microsoft.TestPlatform.TestHost and use
MSBuild pack properties instead.

- IncludeBuildOutput=false (the package bundles the testhost runtime output, not
  its own TestHost assembly)
- ObjectModel is a real net8.0 dependency (conditioned to the .NET build so the
  net462 group stays empty, matching the old nuspec)
- testhost / testhost.x86 project references are kept to produce the bundled
  output but removed from the resolved dependency list (PrivateAssets is not
  honored for these exe references), so they do not leak as NuGet dependencies
- Bundle via TargetsForTfmSpecificContentInPackage (net8.0 inner build): platform
  assemblies + CommunicationUtilities/CrossPlatEngine/Common satellites into
  lib\net8.0, msdia140 natives into lib\net8.0\{x86,x64,arm64}, the testhost
  launchers into build\net8.0\{x64,x86} and the props/targets into build\net8.0
- Ship README.md, ThirdPartyNotices.txt and the lib\net462\_._ stub via Pack items
- Delete Microsoft.TestPlatform.TestHost.nuspec

Package contents and dependency groups verified identical to the previous nuspec
output (65 files; net8.0 -> ObjectModel, net462 empty).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate Microsoft.TestPlatform package from nuspec to MSBuild pack

Replace the hand-written 535-line Microsoft.TestPlatform.nuspec with MSBuild
pack: the 487 <file> elements are translated to <None Pack=true> items that
map the same build outputs to the same package paths, producing a byte-identical
553-file layout (verified against the pre-change package).

- Remove NuspecFile/NuspecBasePath and the NuspecProperty ItemGroup
- IncludeBuildOutput=false (container project, ships no assembly of its own)
- SuppressDependenciesWhenPacking=true (package has no NuGet dependencies)
- Add PackageReadmeFile and explicit None items for README, LICENSE_VS.txt
  (PackageLicenseFullPath is not auto-packed) and ThirdPartyNotices.txt
- Clear the inherited MIT PackageLicenseExpression so the file license applies
- NoWarn NU5100/NU5109/NU5118/NU5128 (assemblies/content outside lib, no deps)
- Recursive ** globs reproduced with folder PackagePath (RecursiveDir preserved)
- Delete Microsoft.TestPlatform.nuspec

Pack now auto-adds a benign <frameworkAssemblies> entry
(System.Runtime.InteropServices.RuntimeInformation for net48/net481) that the
old nuspec omitted; it does not affect the packaged files.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate Microsoft.TestPlatform.Portable package from nuspec to MSBuild pack

Replace the hand-written 657-line Microsoft.TestPlatform.Portable.nuspec with
MSBuild pack: the 601 <file> elements are translated to <None Pack=true> items
that map the same build outputs to the same package paths, producing a
byte-identical 608-file layout (verified against the pre-change package).

- Remove NuspecFile/NuspecBasePath and the NuspecProperty ItemGroup
- IncludeBuildOutput=false, SuppressDependenciesWhenPacking=true (container, no deps)
- Add PackageReadmeFile and explicit None items for README and LICENSE_VS.txt
- Clear the inherited MIT PackageLicenseExpression so the file license applies
- NoWarn NU5100/NU5109/NU5118 (NU5128 was already present)
- Delete Microsoft.TestPlatform.Portable.nuspec

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Add clarifying comment in vstest.console Program.Run (no-op)

Add a comment documenting the existing UTF-8 console-encoding behavior. This
is a comment-only change with no functional impact; it exists to exercise the
full CI pipeline (code-path checks are skipped for doc-only changes).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Migrate Microsoft.TestPlatform.CLI package from nuspec to MSBuild pack

Replaces the three hand-written nuspec variants
(Microsoft.TestPlatform.CLI.nuspec / .sourcebuild.nuspec / .sourcebuild.product.nuspec)
with csproj-based packaging, completing the migration started in microsoft#16125 / microsoft#16132
(issue microsoft#15650).

Each <file src target> element is translated to a <None Pack="true" PackagePath="...">
item. Because everything ships under contentFiles, every content item carries
BuildAction=None / PackageCopyToOutput=true / PackageFlatten=false so pack emits
per-file <contentFiles> entries that are functionally equivalent to the original
generic "**/*.*" copyToOutput/flatten/buildAction wildcard.

The Windows full content (net10.0 layout + net46x/net4x TestHostNetFramework hosts)
is gated on (!DotNetBuildSourceOnly and Windows); the cross-platform $(NetCurrent)
content (mirroring the two identical sourcebuild nuspecs) is gated on
(DotNetBuildSourceOnly or non-Windows). Container settings IncludeBuildOutput=false
and SuppressDependenciesWhenPacking=true are used (the package ships no assembly of
its own and has no NuGet dependencies). The existing ProjectReference, PackageReference
and CopyFiles staging logic is unchanged.

Validation: a clean `build.cmd -c Release -pack` produces a CLI package whose file
list is byte-for-byte identical to the pre-migration package (483 entries, no
eng/expected-*.json drift). The auto-added <frameworkAssemblies> entry is benign and
not part of the file-list oracle. The sourcebuild/VMR variants only execute under
-DotNetBuildSourceOnly / VMR builds and cannot be exercised by a local Windows build;
they are translated faithfully but validated only by inspection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CLI pack: resolve content wildcards at pack time, not evaluation time

The initial CLI migration used MSBuild item wildcards in static <ItemGroup>s
(`net462\System*.dll` for the Windows variant and the `**\*.resources.dll`
source-build resource globs). Static item wildcards are expanded during project
*evaluation*, which happens before the referenced projects' outputs have been
copied into this project's OutputPath. On a clean CI build the folders are empty
at that point, so the wildcards matched nothing and the Windows CLI package shipped
100 fewer files (383 instead of 483), failing verify-nupkgs.ps1. Locally the bug was
masked because a prior build had already populated the output folders.

Explicit (non-wildcard) <None> includes are literal items resolved at pack time, so:
- The Windows `net462\System*.dll` glob is expanded into explicit <None> items
  (matching the pattern already used by Microsoft.TestPlatform.csproj).
- The source-build localized satellite resources (which cannot be enumerated from a
  Windows build) are moved into a TargetsForTfmSpecificContentInPackage target, the
  repo's established pack-time content hook (see Microsoft.CodeCoverage.csproj). It is
  gated to $(NetCurrent) so the content is added exactly once, and %(RecursiveDir)
  preserves the language sub-folders.

Validated with a clean `build.cmd -c Release -pack` (artifacts/bin and
artifacts/packages deleted first to reproduce the CI state): the CLI package is again
byte-for-byte identical to the pre-migration package (483 entries) with no
eng/expected-*.json drift.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Fix CLI package: correct TestHostRuntimeProvider casing; clarify pack-time TFM scoping

Addresses PR review feedback and a package-diff regression.

1. Casing fix (real bug). The runtime provider assembly is
   `Microsoft.TestPlatform.TestHostRuntimeProvider.dll` (capital `H`), but two `<None Include>`
   items copied a casing typo from the old nuspec's `src` attribute and used lowercase
   `TesthostRuntimeProvider.dll`. NuGet nuspec packing used the real on-disk name (capital `H`),
   whereas MSBuild pack ships the literal `Include` casing, so the new Windows package shipped
   the DLL as `Testhost...` and on case-sensitive filesystems (source-build / non-Windows) the
   literal include would not match the built file at all, dropping the DLL. Both occurrences
   (net10.0 Windows item and the $(NetCurrent) source-build item) are corrected to `TestHost`.
   The earlier byte-identical check missed this because PowerShell's Compare-Object is
   case-insensitive; an ordinal comparison now shows the package matches the pre-migration
   layout exactly (483 entries, zero case-sensitive diffs).

2. Pack-time resource globs (review comments, no code change needed). The reviewer flagged that
   the `$(OutputPath)**` resource globs in `_IncludeCliSourceBuildResources` could span other TFM
   subfolders. They cannot: the target runs via TargetsForTfmSpecificContentInPackage in the inner
   per-TFM build, where `$(OutputPath)` already resolves to the per-TFM directory
   (e.g. `...\Release\net11.0\`), so the globs only ever match that single TFM and `%(RecursiveDir)`
   is just the language folder (cs, de, ...). Verified empirically. Added a comment documenting this.

Validated with a clean `build.cmd -c Release -pack` (artifacts deleted first): build succeeds,
verification passes, no eng/expected-*.json drift, CLI package byte/layout-identical to the
pre-migration package under an ordinal (case-sensitive) comparison.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

Consider moving away from nuspec

3 participants