Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [vNext] - 2026-10-30

This is a patch release that makes the MTP package-validation tests prepare their own Codebelt.Coverlet.MTP package during local builds, including Visual Studio Test Explorer runs, with no runtime or package behavior changes.

### Added

- Add automatic preparation of the Codebelt.Coverlet.MTP package for the MTP package-validation tests during local builds, skipped for IDE design-time builds, with isolated output under `artifacts/validation` per configuration and framework.

### Changed

- Change the validation tests to read the package folder from MSBuild metadata instead of a hard-coded `artifacts/package/<configuration>` path, with missing-package guidance that points to `-p:PrepareValidationPackage=true` or an existing package,
- Disable automatic package preparation in GitHub Actions so validation consumes the downloaded release package, while allowing opt-out outside GitHub Actions with `-p:PrepareValidationPackage=false`,
- Document the automatic packing behavior and opt-out in `CONTRIBUTING.md`, replacing the manual `dotnet pack` step.

## [10.1.1] - 2026-10-20

This is a patch release that fixes module unload mutex collisions between unrelated coverage sessions and updates the Microsoft runtime pins and the `System.Security.Cryptography.Pkcs` override used by coverlet.core, with no new capabilities.
Expand Down Expand Up @@ -97,6 +111,7 @@ This is a minor release focused on the Codebelt.Coverlet.MTP fork with narrowed
- .vscode/settings.json configuration,
- .devcontainer legacy configuration.

[10.1.2]: https://github.com/codebeltnet/coverlet/compare/v10.1.1...vNext

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Release heading is not clickable

The new [vNext] heading has no matching link definition because this definition uses [10.1.2]. Readers cannot follow the heading to the release comparison. Rename the definition to [vNext].

Suggested change
[10.1.2]: https://github.com/codebeltnet/coverlet/compare/v10.1.1...vNext
[vNext]: https://github.com/codebeltnet/coverlet/compare/v10.1.1...vNext
Prompt To Fix With AI
This is a comment left during a code review.
Path: CHANGELOG.md
Line: 114

Comment:
**Release heading is not clickable**

The new `[vNext]` heading has no matching link definition because this definition uses `[10.1.2]`. Readers cannot follow the heading to the release comparison. Rename the definition to `[vNext]`.

```suggestion
[vNext]: https://github.com/codebeltnet/coverlet/compare/v10.1.1...vNext
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Codex

[10.1.1]: https://github.com/codebeltnet/coverlet/compare/v10.1.0...v10.1.1
[10.1.0]: https://github.com/codebeltnet/coverlet/compare/v10.0.1...v10.1.0
[10.0.1]: https://github.com/codebeltnet/coverlet/compare/v10.0.0...v10.0.1
4 changes: 3 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ dotnet pack src/coverlet.MTP/coverlet.MTP.csproj -c Release --no-build
dotnet test -c Release --no-build
```

The MTP package-validation tests consume the locally packed `Codebelt.Coverlet.MTP` package from `artifacts/package/release`, so pack before running `test/coverlet.MTP.validation.tests` directly.
The MTP package-validation project automatically packs `Codebelt.Coverlet.MTP` when built locally, including builds started by Visual Studio Test Explorer. No manual packing or package-folder cleanup is required. Each configuration and test framework uses an isolated directory under `artifacts/validation`, so older packages in `artifacts/package` do not affect local validation. The first build takes longer because it builds the package for all supported frameworks; subsequent package builds reuse their build outputs.

In GitHub Actions, automatic packing is disabled so validation consumes the downloaded release package from `artifacts/package/release`. Outside GitHub Actions, use `-p:PrepareValidationPackage=false` to validate an existing package from `artifacts/package/<configuration>` instead. That directory must contain exactly one `Codebelt.Coverlet.MTP.*.nupkg`. As usual, `dotnet test --no-build` reuses the package prepared by the previous build.

## Focused test runs

Expand Down
13 changes: 13 additions & 0 deletions test/coverlet.MTP.validation.tests/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,17 @@
<VSTestTestCaseFilter></VSTestTestCaseFilter>
</PropertyGroup>

<!-- Run for each real framework build, never for IDE design-time builds. -->
<Target Name="PrepareCoverletValidationPackage"
AfterTargets="Build"
Condition="'$(TargetFramework)' != '' and '$(DesignTimeBuild)' != 'true' and '$(PrepareValidationPackage)' == 'true'">
<ItemGroup>
<_PreviousValidationPackages Include="$(ValidationPackagePath)/Codebelt.Coverlet.MTP.*.nupkg;$(ValidationPackagePath)/Codebelt.Coverlet.MTP.*.snupkg" />
</ItemGroup>
<Delete Files="@(_PreviousValidationPackages)" />
<!-- A locally rebuilt package can keep its version; do not reuse the consumer's cached copy. -->
<RemoveDir Directories="$(TargetDir)TestProjects/BasicTestProject/.packages/codebelt.coverlet.mtp" />
<Exec WorkingDirectory="$(RepoRoot)"
Command="dotnet pack &quot;$(RepoRoot)src/coverlet.MTP/coverlet.MTP.csproj&quot; --configuration &quot;$(Configuration)&quot; --artifacts-path &quot;$(ValidationArtifactsPath)/build&quot; --output &quot;$(ValidationPackagePath)&quot; --nologo" />
</Target>
</Project>
15 changes: 7 additions & 8 deletions test/coverlet.MTP.validation.tests/HelpCommandTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public HelpCommandTests()

// Get repository root
_repoRoot = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", ".."));
_localPackagesPath = Path.Combine(_repoRoot, "artifacts", "package", _buildConfiguration.ToLowerInvariant());
_localPackagesPath = ValidationPackage.DirectoryPath;

_projectOutputPath = Path.Combine(_repoRoot, "artifacts", "bin", s_projectName, _buildConfiguration.ToLowerInvariant());

Expand All @@ -58,21 +58,21 @@ public HelpCommandTests()

private protected static string GetPackageVersion(string filter)
{
string packagesPath = TestUtils.GetPackagePath(TestUtils.GetAssemblyBuildConfiguration().ToString().ToLowerInvariant());
string packagesPath = ValidationPackage.DirectoryPath;

if (!Directory.Exists(packagesPath))
{
throw new DirectoryNotFoundException($"Package directory '{packagesPath}' not found, run 'dotnet pack' on repository root");
throw new DirectoryNotFoundException($"Package directory '{packagesPath}' not found. Supply the existing Codebelt.Coverlet.MTP package in this directory, or rebuild the validation test project locally with -p:PrepareValidationPackage=true to prepare it automatically.");
}

List<string> files = Directory.GetFiles(packagesPath, filter).ToList();
if (files.Count == 0)
{
throw new InvalidOperationException($"Could not find any package using filter '{filter}' in folder '{Path.GetFullPath(packagesPath)}'. Make sure 'dotnet pack' was called.");
throw new InvalidOperationException($"Could not find any package using filter '{filter}' in folder '{Path.GetFullPath(packagesPath)}'. Supply the existing Codebelt.Coverlet.MTP package in this directory, or rebuild the validation test project locally with -p:PrepareValidationPackage=true to prepare it automatically.");
}
else if (files.Count > 1)
{
throw new InvalidOperationException($"Found more than one package using filter '{filter}' in folder '{Path.GetFullPath(packagesPath)}'. Make sure 'dotnet pack' was only called once.");
throw new InvalidOperationException($"Found more than one package using filter '{filter}' in folder '{Path.GetFullPath(packagesPath)}'. Expected exactly one.");
}
else
{
Expand Down Expand Up @@ -442,16 +442,15 @@ private async Task EnsureTestProjectBuilt()

private void EnsurePackagesBuilt()
{
string packagesPath = TestUtils.GetPackagePath(
TestUtils.GetAssemblyBuildConfiguration().ToString().ToLowerInvariant());
string packagesPath = ValidationPackage.DirectoryPath;

// Check for Codebelt.Coverlet.MTP
string[] mtpPackages = Directory.GetFiles(packagesPath, "Codebelt.Coverlet.MTP.*.nupkg");
if (mtpPackages.Length == 0)
{
throw new InvalidOperationException(
$"Codebelt.Coverlet.MTP package not found in '{packagesPath}'.\n" +
$"Run: dotnet pack src/coverlet.MTP -c {_buildConfiguration}");
"Supply the existing Codebelt.Coverlet.MTP package in this directory, or rebuild the validation test project locally with -p:PrepareValidationPackage=true to prepare it automatically.");
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ protected MtpValidationTestBase()
#endif
RepoRoot = Path.GetFullPath(
Path.Combine(Directory.GetCurrentDirectory(), "..", "..", "..", ".."));
LocalPackagesPath = Path.Combine(
RepoRoot, "artifacts", "package", BuildConfiguration.ToLowerInvariant());
LocalPackagesPath = ValidationPackage.DirectoryPath;
}

// ── Package version ──────────────────────────────────────────────────────
Expand All @@ -45,14 +44,14 @@ protected string GetCoverletMtpPackageVersion()
if (!Directory.Exists(LocalPackagesPath))
{
throw new DirectoryNotFoundException(
$"Local packages path '{LocalPackagesPath}' not found. Run 'dotnet pack' first.");
$"Local packages path '{LocalPackagesPath}' not found. Supply the existing Codebelt.Coverlet.MTP package in this directory, or rebuild the validation test project locally with -p:PrepareValidationPackage=true to prepare it automatically.");
}

string[] packages = Directory.GetFiles(LocalPackagesPath, "Codebelt.Coverlet.MTP.*.nupkg");
if (packages.Length == 0)
{
throw new InvalidOperationException(
$"Could not find Codebelt.Coverlet.MTP package in '{LocalPackagesPath}'. Run 'dotnet pack' first.");
$"Could not find Codebelt.Coverlet.MTP package in '{LocalPackagesPath}'. Supply the existing Codebelt.Coverlet.MTP package in this directory, or rebuild the validation test project locally with -p:PrepareValidationPackage=true to prepare it automatically.");
}

if (packages.Length > 1)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright (c) Toni Solarin-Sodara
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Reflection;

namespace Coverlet.MTP.validation.tests;

internal static class ValidationPackage
{
// MSBuild selects an isolated local package or the downloaded CI release artifact.
internal static string DirectoryPath { get; } = typeof(ValidationPackage).Assembly
.GetCustomAttributes<AssemblyMetadataAttribute>()
.Single(attribute => attribute.Key == "ValidationPackagePath").Value
?? throw new InvalidOperationException("Validation package path is missing. Rebuild the validation test project.");
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@
<TestingPlatformDotnetTestSupport>true</TestingPlatformDotnetTestSupport>
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
<IsPackable>false</IsPackable>
<!-- Package inputs live outside this project, so always let MSBuild prepare them. -->
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
<PrepareValidationPackage Condition="'$(PrepareValidationPackage)' == '' and '$(GITHUB_ACTIONS)' == 'true'">false</PrepareValidationPackage>
<PrepareValidationPackage Condition="'$(PrepareValidationPackage)' == ''">true</PrepareValidationPackage>
<!-- Isolate both frameworks from each other and from normal solution builds. -->
<ValidationArtifactsPath>$(RepoRoot)artifacts/validation/$(Configuration)/$(TargetFramework)</ValidationArtifactsPath>
<ValidationPackagePath Condition="'$(PrepareValidationPackage)' == 'true'">$(ValidationArtifactsPath)/packages</ValidationPackagePath>
<ValidationPackagePath Condition="'$(PrepareValidationPackage)' != 'true'">$(RepoRoot)artifacts/package/$(Configuration.ToLowerInvariant())</ValidationPackagePath>
<IsTestingPlatformApplication>true</IsTestingPlatformApplication>
<!-- replace the xUnit.net native command line experience with the Microsoft Testing Platform command line experience -->
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
Expand All @@ -26,6 +34,7 @@
</ItemGroup>

<ItemGroup>
<AssemblyMetadata Include="ValidationPackagePath" Value="$(ValidationPackagePath)" />
<ProjectCapability Include="TestingPlatform" />
<ProjectCapability Include="TestingPlatformApplication" />
</ItemGroup>
Expand Down
Loading