From 7ed3d1d27201a205d603af6b1bc126ed56188010 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Sun, 20 Sep 2026 18:11:24 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=92=20add=20version=20and=20trust?= =?UTF-8?q?=20validation=20to=20ci-pipeline=20and=20build=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-pipeline.yml | 118 +++++++++++++++++++++++++++++- Directory.Build.props | 5 ++ 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 2a25068f8..869afc8da 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -20,6 +20,31 @@ jobs: upload-build-artifact-name: build-release timeout-minutes: 45 + release_version_guard: + name: validate-release-version + needs: [build] + runs-on: ubuntu-24.04 + timeout-minutes: 5 + permissions: + contents: read + steps: + - name: Validate calculated release version + shell: bash + env: + RELEASE_VERSION: ${{ needs.build.outputs.version }} + run: | + echo "Calculated release version: ${RELEASE_VERSION}" + + if [[ -z "${RELEASE_VERSION}" ]]; then + echo "::error::Build did not produce a release version." + exit 1 + fi + + if [[ "${RELEASE_VERSION}" =~ ^0\.0\.0-alpha(\.|$) ]]; then + echo "::error::MinVer did not find a valid v-prefixed SemVer tag. Refusing to pack/publish Codebelt.Coverlet.MTP." + exit 1 + fi + test: name: call-test-${{ matrix.os }}-${{ matrix.project_name }} needs: [build] @@ -47,7 +72,7 @@ jobs: pack: name: call-pack - needs: [build, test] + needs: [build, test, release_version_guard] uses: codebeltnet/jobs-dotnet-pack/.github/workflows/default.yml@v3 with: projects: src/coverlet.MTP/coverlet.MTP.csproj @@ -103,6 +128,95 @@ jobs: name: NuGet-Release path: artifacts/package/release + - name: Validate packaged release artifact + shell: bash + env: + RELEASE_VERSION: ${{ needs.build.outputs.version }} + run: | + echo "Calculated release version: ${RELEASE_VERSION}" + + if [[ -z "${RELEASE_VERSION}" ]]; then + echo "::error::Build did not produce a release version." + exit 1 + fi + + if [[ "${RELEASE_VERSION}" =~ ^0\.0\.0-alpha(\.|$) ]]; then + echo "::error::MinVer did not find a valid v-prefixed SemVer tag. Refusing to pack/publish Codebelt.Coverlet.MTP." + exit 1 + fi + + mapfile -t packages < <(find artifacts/package/release -type f -name '*.nupkg' | sort) + + echo "Package files queued for publication:" + if (( ${#packages[@]} == 0 )); then + echo "::error::No .nupkg files were found under artifacts/package/release." + exit 1 + fi + + for package in "${packages[@]}"; do + echo " - ${package}" + done + + if (( ${#packages[@]} != 1 )); then + echo "::error::Expected exactly one .nupkg to publish, found ${#packages[@]}." + exit 1 + fi + + python3 - "${packages[0]}" "${RELEASE_VERSION}" <<'PY' + import os + import sys + import zipfile + import xml.etree.ElementTree as ET + + package_path, expected_version = sys.argv[1], sys.argv[2] + expected_id = "Codebelt.Coverlet.MTP" + expected_filename = f"{expected_id}.{expected_version}.nupkg" + actual_filename = os.path.basename(package_path) + + def fail(message: str) -> "None": + print(f"::error::{message}") + raise SystemExit(1) + + if expected_version.startswith("0.0.0-alpha"): + fail("MinVer did not find a valid v-prefixed SemVer tag. Refusing to pack/publish Codebelt.Coverlet.MTP.") + + if actual_filename != expected_filename: + fail(f"Expected package filename {expected_filename}, found {actual_filename}.") + + with zipfile.ZipFile(package_path) as archive: + nuspec_names = [name for name in archive.namelist() if name.endswith(".nuspec")] + if len(nuspec_names) != 1: + fail(f"Expected exactly one .nuspec inside {actual_filename}, found {len(nuspec_names)}.") + + root = ET.fromstring(archive.read(nuspec_names[0])) + + namespace = {"n": root.tag.split("}", 1)[0][1:]} if root.tag.startswith("{") else None + + def find_text(name: str) -> str | None: + if namespace is None: + return root.findtext(f".//{name}") + + return root.findtext(f".//n:{name}", namespaces=namespace) + + package_id = find_text("id") + package_version = find_text("version") + + if package_id != expected_id: + fail(f"Expected package id {expected_id}, found {package_id!r}.") + + if package_version != expected_version: + fail(f"Expected package version {expected_version}, found {package_version!r}.") + + if package_version.startswith("0.0.0-alpha"): + fail("MinVer fallback version 0.0.0-alpha.0 is not publishable.") + + print(f"Nuspec package id: {package_id}") + print(f"Nuspec package version: {package_version}") + print(f"Validated package file: {actual_filename}") + PY + + echo "PACKAGE_TO_PUBLISH=${packages[0]}" >> "$GITHUB_ENV" + - name: NuGet login (OIDC -> temporary API key) uses: NuGet/login@v1 id: login @@ -113,4 +227,4 @@ jobs: shell: bash env: NUGET_API_KEY: ${{ steps.login.outputs.NUGET_API_KEY }} - run: dotnet nuget push 'artifacts/package/release/*.nupkg' --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push "$PACKAGE_TO_PUBLISH" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate diff --git a/Directory.Build.props b/Directory.Build.props index 6dc02ca5a..748266363 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,6 +2,7 @@ $(MSBuildThisFileDirectory) + $(MSBuildProjectDirectory.ToLower().StartsWith('$(MSBuildThisFileDirectory.ToLower())src')) net472 Debug @@ -46,4 +47,8 @@ true + + v + + From 38374a2f3ee715fdbdb3a24aa1f0f79bebe14449 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Sun, 20 Sep 2026 18:35:40 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=93=9D=20add=20v10.0.1=20changelog=20?= =?UTF-8?q?with=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..e4ae87a34 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,77 @@ +# Changelog + +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). + +## [10.0.1] - 2026-09-20 + +This is a minor release focused on the Codebelt.Coverlet.MTP fork with narrowed scope, enhanced coverage analysis, improved testing infrastructure, and build reliability improvements. + +### Added + +- Codebelt CI/CD pipeline with shared workflow jobs replacing legacy Azure Pipelines, +- Coverage threshold failure messages and exit codes for MTP handler, +- Method coverage calculation and reporting alongside line and branch coverage, +- CoverletCoverageDataProducer for MTP message bus publishing of coverage data, +- Preflight checks for locked and unresolvable assemblies before instrumentation, +- Architecture documentation and diagrams for all integration points, +- Comprehensive unit tests for previously untested internal methods with dependency injection test setup, +- Benchmarks, GitHub Actions, and documentation infrastructure for performance testing, +- Test for [DoesNotReturn] detection in async state machines, +- Dynamic exclusion filters for Coverlet.MTP assemblies to improve filtering reliability, +- netstandard2.0 target framework support for broader compatibility, +- Trace diagnostics via --diag option and actionable warnings for instrumentation, hit, and empty-result failures, +- ResourceStream null guard to improve robustness, +- URL documentation for central testconfig.json configuration, +- MinVer tag prefix configuration for source projects to ensure correct semantic version tag detection during build, +- Pre-publish validation job in CI pipeline to verify calculated release version before packing, +- Comprehensive package artifact validation that verifies package filename, contents, and nuspec metadata match expected values, +- Targeted NuGet package push that publishes only the validated package instead of using wildcard patterns. + +### Changed + +- Rebranded repository to Codebelt.Coverlet.MTP fork with narrowed scope focusing on MTP integration, +- Removed legacy projects, workflows, documentation, and examples to simplify codebase, +- Updated target frameworks to netstandard2.0, net9.0, and net10.0, +- Aligned dependencies to modern framework versions including .NET 10.0.12, +- Enhanced core instrumentation code and capabilities with improved architecture, +- Integrated MTP extension and fixed test isolation issues, +- Updated test infrastructure for modern testing platform (xunit v3, Microsoft.Testing.Platform), +- Improved .NET Framework assembly resolution on Windows, +- Enhanced report output with summary table and console reporters, +- Improved pattern matching branch detection logic and documentation, +- Improved log formatting for multi-line messages in console output, +- Replaced ConcurrentBag with List for unload handlers registry with explicit locking, +- Eliminated phantom branches from async try-finally with await statements, +- Relaxed auto-property skip logic to improve coverage for records, +- Configuration parsing and CoverageConfiguration enhancements, +- Replaced legacy .sln files with modern .slnx format, +- Updated dependencies to latest stable releases across all packages. + +### Fixed + +- Fix silent zero coverage on .NET Framework that occurred since 8.0.0, +- Fix EndOfStreamException in coverage collection, +- Fix pattern matching 'or' synthetic branch detection, +- Fix FieldReference handling in delegate cache branch detection, +- Avoid unnecessary testhost restarts during test execution, +- Normalize Cobertura XML paths to forward slashes for consistency, +- Module restored atomically to prevent loaded assembly corruption, +- Unknown assembly fallback behavior and error handling, +- MTP validation tests infrastructure and test isolation issues, +- Remove skipping UnresolvableDependencies from preflight checks. + +### Removed + +- Legacy .sln solution files (replaced with .slnx format), +- Legacy projects and workflows, +- Documentation files (Changelog.md, GlobalTool.md, KnownIssues.md, MSBuildIntegration.md, VSTestIntegration.md, UnderstandingBranchCoverage.md, Troubleshooting.md, DeterministicBuild.md, etc.), +- Example projects for MSBuild and VSTest integrations, +- CodeQL GitHub Actions workflow (integrated into ci-pipeline.yml), +- Legacy dotnet.yml and other Azure Pipelines workflows, +- Legacy build scripts (scripts/build.ps1, scripts/test.ps1, scripts/report.ps1), +- .vscode/settings.json configuration, +- .devcontainer legacy configuration. + +[10.0.1]: https://github.com/codebeltnet/coverlet/compare/v10.0.0...v10.0.1 From 5c3fd90164c410a6c4093b39bc61ed839b754ae1 Mon Sep 17 00:00:00 2001 From: gimlichael Date: Sun, 20 Sep 2026 18:38:42 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=94=92=20remove=20automatic=20push=20?= =?UTF-8?q?trigger=20from=20ci-pipeline?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-pipeline.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index 869afc8da..10e0edb8b 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -3,8 +3,6 @@ name: Codebelt Coverlet MTP CI on: pull_request: branches: [master] - push: - branches: [master] workflow_dispatch: permissions: