From 1f7d2107167c10912aefa1d640f60c8542c796e6 Mon Sep 17 00:00:00 2001 From: Chris Wolfgang <210299580+Chris-Wolfgang@users.noreply.github.com> Date: Thu, 13 Aug 2026 08:40:25 -0400 Subject: [PATCH] chore: protected-file split for 0.22.0 (release.yaml, coyote.yaml, DBP) Extracts the three protected configuration files from #357 so that PR can pass the `Detect .NET Projects` guard without an admin bypass on all 100 of its files. Contents are byte-identical to chore/fold-testkit; this PR adds no changes of its own. - Directory.Build.props: version centralization for the TestKit fold -- Version/AssemblyVersion/FileVersion/PackageProjectUrl/LangVersion/ SignAssembly/License moved here and removed from the individual csprojs. - .github/workflows/release.yaml: version-check reads Directory.Build.props via the scoped XPath /Project/PropertyGroup/Version. Depends on the above -- the two are one logical change and must land together. - .github/workflows/coyote.yaml: excludes Dispose_racing_enumeration_never_deadlocks, which crashes Coyote 1.7.11's own instrumentation on the ConfiguredCancelableAsyncEnumerable awaiter introduced by #363. See #364. After this merges to main, main merges back into chore/fold-testkit and #357 goes bypass-free. Co-Authored-By: Claude Opus 5 --- .github/workflows/coyote.yaml | 10 ++++++- .github/workflows/release.yaml | 54 +++++++++++++++------------------- Directory.Build.props | 18 ++++++++++++ 3 files changed, 50 insertions(+), 32 deletions(-) diff --git a/.github/workflows/coyote.yaml b/.github/workflows/coyote.yaml index 351a2408..864a47bc 100644 --- a/.github/workflows/coyote.yaml +++ b/.github/workflows/coyote.yaml @@ -78,7 +78,15 @@ jobs: dll="bin/Release/net8.0/Wolfgang.Etl.Abstractions.Tests.Concurrency.dll" methods=( Concurrent_item_count_increments_never_lose_an_update - Dispose_racing_enumeration_never_deadlocks + # Dispose_racing_enumeration_never_deadlocks is DISABLED (#364). + # Coyote 1.7.11 throws a NullReferenceException inside its own + # CoyoteRuntime.IsTaskUncontrolled when it meets the + # ConfiguredCancelableAsyncEnumerable awaiter that the ConfigureAwait(false) + # fix (#363) introduced in ExtractorBase.ExtractWithResetAsync. It is an + # instrumentation crash, not a race we found: "Found 1 bug" on iteration #1, + # 1 execution path explored, 0.096 sec. Coyote is dormant (1.7.11 is the + # newest on nuget.org; last upstream commit 2024-12-11), so there is no + # version to upgrade to. Re-enable via #364. ) for m in "${methods[@]}"; do echo "::group::coyote test $m ($iterations iterations)" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index c11c8bc4..7fdd62ba 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -42,45 +42,37 @@ jobs: Write-Host "Expected version: $tagVersion" -ForegroundColor Cyan Write-Host "" - $srcCsprojs = @(Get-ChildItem -Path './src' -Recurse -Filter '*.csproj' -ErrorAction SilentlyContinue) - if ($srcCsprojs.Count -eq 0) { - Write-Warning "No src csprojs found - skipping version validation" - exit 0 + # The four packages are lockstep-versioned; is the single source of truth in + # Directory.Build.props (no per-csproj ). Read it there. + $propsPath = './Directory.Build.props' + if (-not (Test-Path $propsPath)) { + Write-Error "Directory.Build.props not found - cannot resolve the package version" + exit 1 } - # Collect and values from every src csproj - $found = @() - foreach ($proj in $srcCsprojs) { - try { - [xml]$xml = Get-Content $proj.FullName -Raw - $nodes = $xml.SelectNodes('//Version | //PackageVersion') - foreach ($node in $nodes) { - $v = $node.InnerText.Trim() - if ($v) { - $found += [pscustomobject]@{ Project = $proj.Name; Version = $v } - } - } - } catch { - Write-Warning "Failed to parse $($proj.Name): $($_.Exception.Message)" - } - } + [xml]$props = Get-Content $propsPath -Raw + # Scope to PropertyGroup-level (the package version) — NOT a + # child element — and require exactly one distinct value. + $versions = @($props.SelectNodes('/Project/PropertyGroup/Version') | ForEach-Object { $_.InnerText.Trim() } | Where-Object { $_ } | Sort-Object -Unique) - Write-Host "Versions found in src csprojs:" -ForegroundColor Cyan - foreach ($f in $found) { - Write-Host " $($f.Project): $($f.Version)" -ForegroundColor DarkGray + if ($versions.Count -eq 0) { + Write-Error "No property found in Directory.Build.props" + exit 1 } - Write-Host "" - - if ($found.Count -eq 0) { - Write-Error "No or found in any src csproj" + if ($versions.Count -gt 1) { + Write-Error "Multiple distinct values in Directory.Build.props: $($versions -join ', '). There must be exactly one." exit 1 } - if ($found.Version -contains $tagVersion) { - Write-Host "Release tag matches at least one src csproj version" -ForegroundColor Green + $version = $versions[0] + + Write-Host "Repository version (Directory.Build.props): $version" -ForegroundColor Cyan + Write-Host "" + + if ($version -eq $tagVersion) { + Write-Host "Release tag matches the repository version" -ForegroundColor Green } else { - $allVersions = ($found.Version | Sort-Object -Unique) -join ', ' - Write-Error "Release tag '$tagName' (version '$tagVersion') does not match any src csproj version. Found: $allVersions. Bump the csproj or correct the release tag before re-running." + Write-Error "Release tag '$tagName' (version '$tagVersion') does not match the repository version '$version'. Bump in Directory.Build.props or correct the release tag before re-running." exit 1 } diff --git a/Directory.Build.props b/Directory.Build.props index c0579999..9ac84f1f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -90,9 +90,27 @@ (Description, PackageTags, PackageProjectUrl, RepositoryUrl, PackageLicenseExpression, PackageReadmeFile) stay in each src csproj where they are repo-specific. --> + + 0.22.0 + + 1.0.0.0 + $([System.Text.RegularExpressions.Regex]::Replace("$(Version)", "[-+].*$", "")).0 Chris Wolfgang Chris Wolfgang Copyright (c) Chris Wolfgang + + https://github.com/Chris-Wolfgang/ETL-Abstractions + MIT + + False + False + latest git true true