Release v0.2.2: canonical maintenance round + AssemblyVersion fix#134
Merged
Conversation
Template-drift resolution for ETL-FixedWidth — the non-protected half. Re-syncs 16 template-tracked infrastructure files to the canonical repo-template. Excludes docfx_project/* (repo-specific docs), protected config/workflow files (separate PR), and .gitkeep / expected-noise files. Part of #95. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Template-drift resolution for ETL-FixedWidth — the protected half. 3 files that trip the pr.yaml guard, isolated for admin-bypass merge. Part of #95. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…xedWidth)
The C1 drift re-sync brought the canonical CONTRIBUTING.md but left the
template's {{PROJECT_NAME}} placeholder literal. Replace it with this repo's
project name so the synced CONTRIBUTING.md is correct, not a raw template.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fold-down of the repo-template fix (PR #389): Replace-Placeholders now writes with -Encoding utf8NoBOM -NoNewline. Rolled to every repo so the campaign stays consistent with the updated canonical. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Propagates the three files folded into repo-template during drift Phase 0: tests/Directory.Build.props + benchmarks/Directory.Build.props (TreatWarningsAsErrors=false) and tests/.editorconfig (test-project analyzer relaxations). Excluded from the initial C1 sync; rolled out now so every repo matches the canonical template. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Removes the TreatWarningsAsErrors=false override on test projects. The genuinely test-inappropriate analyzer rules are already silenced per-rule in tests/.editorconfig; test code now inherits the root Directory.Build.props (TreatWarningsAsErrors in Release, like src/examples). benchmarks remain exempt for now. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add <Nullable>enable</Nullable> to the root Directory.Build.props and remove the now-redundant per-project <Nullable> lines from every SDK-style csproj. Nullable reference types are configured in one place; a newly added project inherits the setting automatically. Both halves ride this protected branch so they merge atomically — the Directory.Build.props addition and the csproj removals land together, so there is never a window where nullable reference types are off. Legacy non-SDK project files do not import Directory.Build.props and are left untouched with their explicit settings. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Legacy non-SDK .csproj files explicitly import Microsoft.Common.props,
so they DO inherit Directory.Build.props — the earlier unconditional
<Nullable>enable</Nullable> reached projects it should not have:
* F# (.fsproj) / VB (.vbproj) projects — now excluded by conditioning
the property on '$(MSBuildProjectExtension)' == '.csproj'.
* legacy non-SDK C# example projects (C# 7.3, no nullable support) —
given an explicit <Nullable>disable</Nullable> opt-out, restoring
their pre-hoist state. These are the documented C5 carve-outs.
SDK-style C# projects are unaffected — they still inherit enable from
the single Directory.Build.props.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds queries: security-extended to the CodeQL init step so the broader security query pack runs on top of the default queries. Slightly longer scans, materially more security coverage. Initiative S1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New .github/workflows/stryker.yaml runs Stryker.NET against the repo's test projects on workflow_dispatch and a weekly schedule. The workflow is a no-op until a stryker-config.json is added at repo root or under tests/<project>/ — this commit is the canonical infrastructure; per-repo Stryker config is the follow-up. Initiative T3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a verify-docs-build job to release.yaml that runs DocFX without deploying (metadata + build + output check). publish-nuget now needs [pack-and-validate, verify-docs-build] so a broken docs build blocks the release before the NuGet package goes live. If a repo has no docfx_project/docfx.json, the job no-ops with a notice; this is the canonical infrastructure, with per-repo docs coverage tracked separately. Initiative D8. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Append a github-actions package-ecosystem to .github/dependabot.yml so Dependabot opens weekly PRs to bump pinned action versions in the repo's GitHub workflows. Grouped under a single PR per week. Existing nuget ecosystems are left unchanged. Initiative CI2. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Keep-a-Changelog skeleton with an [Unreleased] section so release notes can accumulate here between releases instead of being lost. Follows the canonical format used across the fleet. Initiative D3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a guard step to docfx.yaml that fetches the currently-deployed versions.json from gh-pages and confirms the newly-generated one has at least as many entries AND retains every previously-published version label. Aborts the deploy if the version selector would shrink or lose entries. If no existing versions.json is found (first deploy), the step no-ops with a notice. Initiative D6. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add the Microsoft.CodeAnalysis.PublicApiAnalyzers package plus opt-in AdditionalFiles globbing for PublicAPI.Shipped.txt / Unshipped.txt to the root Directory.Build.props. The AdditionalFiles use Exists() conditions, so the analyzer activates per-project only when those files are present. Library projects opt in by dropping the two text files into the src directory; test, example, and benchmark projects stay dormant. Per-repo enablement (populate Unshipped.txt with the current public API surface) is tracked as a separate follow-up maintenance issue. Initiative A1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add fleet-canonical defaults to root Directory.Build.props: - Authors / Company / Copyright (uniform across the fleet; per-csproj values still win where set explicitly). - RepositoryType=git, PublishRepositoryUrl=true. - IncludeSymbols=true + SymbolPackageFormat=snupkg so .snupkg ships with every .nupkg. - EmbedUntrackedSources=true to capture generated sources in PDBs. - ContinuousIntegrationBuild=true under $(CI)=true (deterministic build flag, set by GitHub Actions). - Microsoft.SourceLink.GitHub package so debuggers can step from NuGet-installed code straight to GitHub source. Repo-specific NuGet fields (Description, PackageTags, PackageProjectUrl, RepositoryUrl, PackageLicenseExpression, PackageReadmeFile) stay in per-src csproj where they belong and are tracked as per-repo follow-up maintenance issues. Initiative CI3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a docfx.yaml step that runs the test suite with Cobertura coverage collection and generates a ReportGenerator HTML report into docfx_project/_site/coverage/ before the deploy step. The published docs site gains a /coverage/ subpath alongside the existing /api/. continue-on-error keeps a coverage failure from blocking the docs deploy; if no test projects are present the step no-ops. Initiative T1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- BannedSymbols.txt: replace {{PROJECT_NAME}} placeholder with the repo's
package name (skipped on repo-template where the placeholder is the
intended template artifact).
- docfx.yaml: 'exit 1' inside the deploy try-block changed to 'throw' so
the outer finally always unsets the global http.extraheader token; added
$LASTEXITCODE checks after git fetch / git worktree add / git init /
git remote add so a setup failure surfaces a clear error.
Fan-out of the round-2 Copilot fixes verified against DateTime-Extensions
(#178 / #179 pilot).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- scripts/Setup-BranchRuleset.ps1: jq filter wrapped in '[ .[] | select() ]' so the output is always valid JSON even with multiple matches; gh stderr redirected to a temp file so it can't poison stdout. - scripts/Fix-BranchRuleset.ps1: same stderr-isolation fix on the rulesets fetch (no more '2>&1' merge). - scripts/Validate-DocsDeploy.sh: distinguish 'versions.json never created' from 'versions.json failed validation' in step 4 so the skip message reflects reality. - .github/dependabot.yml: drop the stale 'dotnet' label (no longer in the Setup-Labels.ps1 taxonomy). - REPO-INSTRUCTIONS.md: replace the stale label list (dependabot-*, dotnet) with the current Maintenance-framework labels Setup-Labels.ps1 actually creates. IAsyncEnumerable-Extensions also gets README.md / CONTRIBUTING.md updated to point at docs/README-FORMATTING.md since the root copy was removed by the earlier D7 cleanup. Fan-out of the round-2 Copilot fixes verified against DateTime-Extensions (#178 pilot). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- .github/workflows/stryker.yaml: replace literal-in-array config detection with explicit [ -f ] checks. nullglob only drops words that look like globs (contain *, ?, [); the bare literal 'stryker-config.json' was preserved unconditionally, so the workflow would mark found=true and attempt to install Stryker even on repos with no config. - actions/checkout@v4 -> @v6 and setup-dotnet@v4 -> @v5 for consistency with the rest of the fleet's workflows. Fan-out of the round-2 Copilot fixes verified against DateTime-Extensions (#181 pilot). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
stryker.yaml lives under .github/workflows/*, which means it trips the pr.yaml "Detect .NET Projects" guard the same way the rest of canonical-protected does. Keeping T3 on its own branch would have meant two admin-bypass merges per repo (canonical-protected -> main, then t3-stryker -> main). Folding T3 in here collapses that to one bypass on the way to release. Merges origin/t3-stryker-mutation-testing into canonical-protected. The existing per-repo T3 PR will be closed as superseded once this lands.
These scripts were run once when this repo was bootstrapped from repo-template and are not needed afterward: - scripts/setup.ps1 (orchestrator for the others) - scripts/Setup-Maintenance.ps1 (created the Maintenance issues) - scripts/Setup-BranchRuleset.ps1 (created the main branch ruleset) - scripts/Setup-GitHubPages.ps1 (bootstrapped gh-pages branch) - scripts/templates/maintenance-parent-body.md (template used by Setup-Maintenance) repo-template keeps these files — they remain available there so any new repo created from the template can still run them at bootstrap. Recurring utilities are intentionally kept: Setup-Labels.ps1 (idempotent), Fix-BranchRuleset.ps1, format.ps1, Validate-DocsDeploy.sh, build-pr.ps1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add '$(UsingMicrosoftNETSdk)' == 'true' to the existing .csproj-only condition so the property only applies to SDK-style projects. Legacy non-SDK csproj files no longer pick up <Nullable>enable</Nullable> by inheritance; they would have to opt in explicitly. Verified safe by piloting on IComparable-Extensions — full Release build + 540-test run (54 tests x 10 TFMs) passed cleanly with the tightened condition. Resolves the PR-#390 review thread that asked for this addition. The per-repo explicit <Nullable>disable</Nullable> opt-outs already in place on Try-Pattern (examples/CSharp.DotNet462.Example) and D20-Dice (examples/Net4.8/Example1-Console) become redundant but harmless under this condition — they can be cleaned up later, or left as belt-and- suspenders documentation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings the canonical Directory.Build.props in line with repo-template and D20-Dice, which carry an explanatory comment above the <Nullable> line describing what the .csproj + $(UsingMicrosoftNETSdk) condition excludes and where the remaining opt-out path lives. No behavior change — comment only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
T3's stryker.yaml was cherry-picked carrying actions/upload-artifact@v4, while pr.yaml/release.yaml/codeql.yaml all use @v7. Bumping for consistency with the fleet's canonical action versions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The flag is a Windows-PowerShell-5.1-only switch; pwsh (PowerShell 7+) treats it as unsupported and errors. The step runs under shell: pwsh, so the call must omit it. (Already correct in the alternate path elsewhere in this workflow — bringing this one in line.) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`dotnet tool install -g` errors with a non-zero exit code if the tool is already installed (common on self-hosted runners and after prior steps). Even with stderr redirected, the exit code can break subsequent invocations. Switch to update-or-install: try update first (succeeds if installed), fall back to install if not. The step runs under shell: pwsh so the pwsh 7 || operator is available. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Get-ChildItem -Filter '*.sln' missed .slnx solutions, causing the restore/build warm-up to silently skip in repos using the newer solution format (e.g. IComparable-Extensions). Switching to a filter that accepts both extensions so DocFX gets a compiled solution to extract metadata from. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
build-all-versions.yaml built versions.json from every SemVer tag in the repo, regardless of whether the per-tag build succeeded. A failed worktree add or empty DocFX output would silently leave the version-picker linking to /versions/<tag>/ paths that never existed on gh-pages. Now filter $orderedTags against the directories actually present under $outDir/versions/. Missing tags get a ::notice:: log entry so the skip is visible in workflow output, but versions.json only references real paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The catch block was treating ANY Invoke-WebRequest failure as "first
deploy, skipping preservation check" — transient network/DNS/Pages
outages, auth issues, redirect loops, etc. all silently bypassed the
safety check, defeating its purpose. A deploy that drops versions
from the picker could slip through any of those scenarios.
Now inspect $_.Exception.Response.StatusCode:
- 404 → genuine "first deploy" case, skip preservation check (exit 0)
- anything else → abort the deploy (exit 1) so a real issue surfaces
instead of silently weakening the guard.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Jun 26, 2026
Replace the empty Keep-a-Changelog skeleton with concrete entries for v0.1.0, v0.2.0, and v0.2.1 (sourced from the GitHub release notes) plus an [Unreleased] section capturing the pending Abstractions 0.14.1 upgrade and the canonical maintenance round. Closes #109 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Audited README.md and the non-README markdown against the current code and package metadata: - Broken links: Formatting Guide and "detailed formatting guidelines" pointed at root README-FORMATTING.md; the file lives at docs/README-FORMATTING.md. - Wrong script path: `pwsh ./format.ps1` -> `pwsh ./scripts/format.ps1`. - Target Frameworks table listed the CI test matrix (net47x/48, net5-9) as if they were package targets. Replaced with the real package TFMs (net462;net481;netstandard2.0;net8.0;net10.0) and a note clarifying the tested-against runtimes. - Build prerequisite said ".NET 8.0 SDK"; net10.0 target needs the 10.0 SDK. - LoadAsync snippet used an undeclared `sourceItems`; added a comment noting it takes an IAsyncEnumerable<T> (a List will not compile). - docfx introduction.md claimed netstandard2.1/net9.0 targets; corrected to the actual TFMs. Closes #111 Closes #112 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Re-sync the files where this repo had fallen behind the canonical repo-template. Verified locally: src + test Release build clean (0 warnings) and 303/303 tests pass with the analyzer bumps. Synced: - Directory.Build.props: Meziantou.Analyzer 3.0.85->3.0.98, SonarAnalyzer.CSharp 10.25->10.27, Microsoft.SourceLink.GitHub 8.0.0->10.0.300 - codeql.yaml: github/codeql-action init/analyze @V3 -> @v4 - stryker.yaml: full canonical sync (windows-latest so net4x TFMs compile, full SDK matrix, pwsh test-project auto-discovery, umbrella/per-project config modes) — byte-identical to repo-template - benchmarks.yaml: concurrency group -> `gh-pages` (shared cross-workflow group so docfx/release gh-pages publishes don't race) - .gitignore: generalize `_site/` to any depth + ignore auto-generated `docfx_project/api/*.yml` metadata Intentional deviations left as-is (documented in the PR): - benchmarks.yaml "Detect benchmark project" gate — skipped; this repo is the benchmarks reference impl and always has the project present - pr.yaml — template-only self-skip guards; downstream correctly omits them - BannedSymbols.txt / CONTRIBUTING.md — only resolved {{PROJECT_NAME}} placeholders + a correct repo-specific SDK note Closes #95 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a root umbrella stryker-config.json so the canonical stryker.yaml workflow (and `dotnet stryker` locally) runs reproducibly against the unit-test project. Baseline run (dotnet-stryker 4.15.0, net10.0, Standard mutation level): Mutation score: 72.87% Killed 491 | Survived 153 | Timeout 22 | NoCoverage 38 | CompileError 21 | Ignored 186 Surviving/uncovered mutants by file (triage): FixedWidthLineParser.cs 57 survived, 19 no-coverage, 8 timeout FixedWidthExtractor.cs 35 survived, 12 no-coverage FixedWidthLoader.cs 30 survived, 6 no-coverage FixedWidthConverter.cs 15 survived, 1 no-coverage, 10 timeout (remainder: FieldDescriptor/FieldMap/attributes — single digits) Closes #107 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Static analysis of the test and benchmark projects for dead code. The only finding: the `IntRecord` record in FixedWidthProgressTests.cs was never referenced anywhere (no test, no [MemberData]/[ClassData], no nameof) — a speculative "available for any tests that need a minimal record type" helper that was never adopted. Its file contained nothing else, so the whole file is removed. The benchmark project has no dead code: every [Benchmark] class is discovered by BenchmarkSwitcher.FromAssembly, both POCOs are used, and all [GlobalSetup]/ [Params]/private helpers are referenced. Verified: 303/303 tests still pass, Release build clean. Closes #102 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an `inspectcode` job that runs JetBrains ReSharper InspectCode in PARALLEL with the test stages (no `needs:` on them, only on detect-projects). Findings upload to GitHub Code Scanning as SARIF and annotate the PR diff. - runs-on windows-latest: the src/test projects target net462/net481, which a Linux runner cannot build (same reason codeql.yaml uses windows). - Mirrors the repo's pull_request_target trusted-checkout model: checks out the PR head, then overwrites protected configs from main — `*.DotSettings` added to that trusted list so a PR cannot weaken the InspectCode profile. - Gates only on `error`-severity findings; warnings surface in Code Scanning but do not block (tune up once the noise floor settles). - `ETL Fixed Width.slnx.DotSettings`: starter noise-floor profile silencing rules already owned by the Roslyn stack (.editorconfig formatting, IDE1006 naming, RedundantUsing, and public-surface "unused" rules governed by PublicApiAnalyzers). Notes: - pr.yaml only runs under pull_request_target on PRs to `main`, so this job is first exercised when vNext -> main (PR #134) runs; it cannot be CI-validated on a PR to vNext. The DotSettings noise-floor and the `--format=sarif` flag should be tuned after that first real run. - Making "ReSharper InspectCode" a REQUIRED status check on `main` is a separate branch-ruleset admin action (not done here). Closes #178 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chore: bump Abstractions to 0.14.1 and TestKit/Xunit to 0.9.0
docs: seed CHANGELOG with release history (D2, #109)
chore: resolve template drift vs repo-template (C1, #95)
test: add Stryker config + record baseline mutation score (T3, #107)
test: remove dead IntRecord test POCO (C8, #102)
ci: add ReSharper InspectCode parallel job to pr.yaml (#178)
…sedes #185) Folds the two analyzer bumps from Dependabot PR #185 onto the v0.2.2 vNext train. #185's other updates (Abstractions 0.14.1, TestKit/TestKit.Xunit 0.9.0) already landed on vNext via #177 — but Dependabot couldn't merge #185 to main because the 0.14.1 IDisposable change needs code reconciliation it didn't do (CA1063/CS0108/CS0114/S3881). #177 carries that reconciliation. Bumping here also lifts vNext's analyzer versions to/above main's (main has Meziantou 3.0.105 / VS.Threading 17.14.15), avoiding a downgrade conflict in Directory.Build.props when vNext merges to main (#134). - Meziantou.Analyzer 3.0.98 -> 3.0.115 - Microsoft.VisualStudio.Threading.Analyzers 17.14.15 -> 18.7.23 (major) Verified: src + test Release build clean (0 warnings) across all TFMs; 303/303 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This was referenced Jun 26, 2026
chore: bump Meziantou 3.0.115 + VS.Threading.Analyzers 18.7.23 (supersedes #185)
Reconciles main's independent Dependabot bumps with the vNext release train. Conflict resolutions (newest of each; vNext keeps its required versions): - Directory.Build.props: Meziantou.Analyzer 3.0.115 (vNext, > main's 3.0.105); VS.Threading.Analyzers 18.7.23 auto-merged from vNext. - src csproj: Wolfgang.Etl.Abstractions 0.14.1 (vNext — 0.13.0 would reintroduce the IDisposable build break). - tests csproj: TestKit/TestKit.Xunit 0.9.0 (vNext, required by Abstractions 0.14.1); Microsoft.Extensions.Logging.Abstractions 10.0.9 + coverlet.collector 10.0.1 (main, newer). - stryker-config.json: took main's canonical T3 version (full project path, 90/75 thresholds) over the session-created variant. Verified: src + test Release build clean (0 warnings) across all TFMs; 303/303 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Chris-Wolfgang
added a commit
that referenced
this pull request
Jun 26, 2026
…files chore: protected-file changes for v0.2.2 (split from #134)
This was referenced Jun 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cuts v0.2.2. Supersedes the stacked canonical PRs (canonical-protected, canonical-unprotected, protected/d8-verify-docs-build-fleet, fix/restore-assemblyversion, chore/remove-post-setup-bootstrap-files) — all folded into this vNext → main merge.
Library public API and runtime behavior are unchanged from the previous release. This is canonical CI/docs/metadata work plus the C4 binding-stability fix.
Scope folded into v0.2.2
Added
release.yaml(deduplicated)docs/DOCFX-VERSION-PICKER.md(the D8 bulk fanout dropped this file on some repos; added directly)Changed
<Nullable>enable</Nullable>consolidated intoDirectory.Build.propsgithub-actionsecosystemPackageReferences centralized inDirectory.Build.propsFixed
<AssemblyVersion>1.0.0.0</AssemblyVersion>+ prerelease-safe<FileVersion>— binding stability for .NET Framework consumersverify-docs-build:job key inrelease.yaml.gitattributesmerge conflict resolved by keeping the canonical documented variantPost-merge
v0.2.2and publish GitHub Release →release.yamlfires