Skip to content

Release v0.1.1: canonical maintenance round + AssemblyVersion fix#119

Open
Chris-Wolfgang wants to merge 99 commits into
mainfrom
vNext
Open

Release v0.1.1: canonical maintenance round + AssemblyVersion fix#119
Chris-Wolfgang wants to merge 99 commits into
mainfrom
vNext

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

Cuts v0.1.1. 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.1.1

Added

  • D8 verify-docs-build job in release.yaml (deduplicated)
  • A1 PublicApiAnalyzers scaffolding (baseline file deferred to IDE-fix pass)
  • CI3 canonical NuGet metadata (Authors/Copyright/SourceLink/snupkg)
  • T3 Stryker mutation-testing workflow
  • T1 coverage report published to docs
  • S1 CodeQL security-extended query pack
  • D6 versions.json preservation guard
  • D7 docs build cache hygiene
  • P2 BenchmarkDotNet → gh-pages chart workflow (if benchmarks/ exists)
  • docs/DOCFX-VERSION-PICKER.md (the D8 bulk fanout dropped this file on some repos; added directly)

Changed

  • C1 fleet template-drift sync
  • <Nullable>enable</Nullable> consolidated into Directory.Build.props
  • CI2 Dependabot github-actions ecosystem
  • D3 script hardening
  • Analyzer PackageReferences centralized in Directory.Build.props
  • Removed post-setup bootstrap files (REPO-INSTRUCTIONS.md, scripts/setup.ps1, Setup-BranchRuleset.ps1, Setup-GitHubPages.ps1) — template carry-overs

Fixed

  • C4 restored explicit <AssemblyVersion>1.0.0.0</AssemblyVersion> + prerelease-safe <FileVersion> — binding stability for .NET Framework consumers
  • Duplicate verify-docs-build: job key in release.yaml
  • .gitattributes merge conflict resolved by keeping the canonical documented variant

Post-merge

  1. Tag v0.1.1 and publish GitHub Release → release.yaml fires
  2. Verify NuGet indexing
  3. Delete vNext + close any remaining superseded PRs

Chris-Wolfgang and others added 30 commits May 22, 2026 11:29
Template-drift resolution for System.Mail-Extensions — 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 #80.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Template-drift resolution for System.Mail-Extensions — the protected half. 4 files
that trip the pr.yaml guard, isolated for admin-bypass merge.

Part of #80.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ions.Mail)

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>
.editorconfig dropped the [*.ps1] override on the rationale that pwsh
shebangs (#!/usr/bin/env pwsh) on scripts under scripts/ require LF +
no-BOM to be recognized by the Linux/macOS kernel. .gitattributes still
forced *.ps1 to CRLF, with a comment claiming the two files matched —
that comment is now stale, and editors honoring .editorconfig would
format LF while git normalized to CRLF on commit.

Switching .gitattributes to eol=lf for *.ps1 and updating the comment.
.editorconfig [*] section already provides LF + UTF-8 (no BOM) +
4-space indent for PowerShell scripts.

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>
Chris-Wolfgang and others added 17 commits May 25, 2026 15:36
1. (Stage 1/3 bash, exact-file branch) Added an explicit exit-code
   check around `git show > "$config_file"`. The globbed branch was
   hardened earlier; the exact-file branch had been left silently
   falling back to the PR version on any git show failure.

2. (Stage 1/3 bash, globbed branch) The process substitution
   `done < <(... | grep -E ...)` runs under `set -eo pipefail`, and
   grep exits 1 when no entries match. For repos that don't ship a
   `*.ruleset` (or any other optional pattern), the previously-fine
   "no matches → skip" behavior was actually failing the step.
   Wrapped the grep in `{ ... || true; }` so an empty match is
   treated as zero iterations, not a failure.

3. (Stage 2 pwsh) `Out-File ... -NoNewline` strips trailing newlines
   from the copied workflow/globalconfig/ruleset/editorconfig files,
   producing malformed copies. Removed -NoNewline so the file's
   trailing newline is preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy-Item -Force overwrites files that exist in both source and
destination, but doesn't remove destination-only files. Over multiple
releases — if a docs page or asset is dropped from docfx output —
the stale file lingers indefinitely in gh-pages, served alongside
the current docs.

Adding a clear-before-copy step for both versions/<VERSION_DIR> and
versions/latest. Preserves the directory entry itself so per-release
git diffs stay clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The earlier "Restore dependencies" step already does the restore, so
the implicit restore inside dotnet test is wasted I/O. Adding
--no-restore alongside the existing --no-build to skip both.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The D6 "Verify previous versions preserved in versions.json" guard
ran whenever deploy_to_pages != false. But the deploy step only
touches the root versions.json when deploy_as_latest is ALSO true:

  - deploy_to_pages=false → dry-run, nothing deploys
  - deploy_to_pages=true + deploy_as_latest=false → rebuild a single
    older version; deploy writes only versions/<dir>/, doesn't touch
    the root
  - deploy_to_pages=true + deploy_as_latest=true → full deploy that
    overwrites the root versions.json

The guard exists to protect that root file. In the rebuild-an-older-
version case there's nothing for the guard to protect, but it still
fetched the live Pages versions.json and compared — meaning a
transient Pages fetch/parse error would block a legitimate rebuild.

Tightening the if condition so the guard only runs in the third case
(both inputs true).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Write-Error prefixes its output with PowerShell error formatting
(file/line/category metadata), so a literal ::error::... payload
no longer starts the line — and Actions' workflow-command parser
looks for ::error:: at the BEGINNING of a stream line. The result
was that the missing-versions.json failure produced a red error in
the log but no annotation marker on the run summary.

Switching to Write-Host (literal output, no PowerShell prefixing)
plus the existing exit 1 keeps the annotation visible and still
fails the step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
My earlier Stage 1 hardening kept the integer-only regex [0-9]+% and
the bash integer comparator -lt. ReportGenerator typically emits
decimals like "92.3%" — the regex missed those, and the new
matched_count=0 guard would then fail jobs whose Summary.txt had only
decimal rows. Even after broadening the regex to accept decimals, bash
[ errors with "integer expression expected" on a non-integer value.

Two fixes:

  1. Regex now matches [0-9]+(\.[0-9]+)?% so decimal percents
     count toward matched_count.

  2. Percent is floored to an integer via awk '{print int($1)}'
     before the -lt comparison. Matches Stage 2 pwsh's
     [int][math]::Floor([double]$Matches[2]) semantically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…esets

Fixes two bugs in the canonical-unprotected scripts that were fanned out
from repo-template:

- Setup-Labels.ps1: the ValidatePattern attribute string was left
  unterminated and the [string]$Repository declaration + closing paren
  were dropped, leaving a duplicated script body that ran with
  $Repository unbound. Param block restored to a single well-formed
  declaration; duplicated body removed.

- Fix-BranchRuleset.ps1: gh api --paginate concatenates multiple JSON
  array payloads when results span pages, which breaks ConvertFrom-Json.
  Switched to ?per_page=100 in a single call.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Stage 2 (Windows) coverage gate regex

    ^\s*(\S+)\s+.*(\d+(?:\.\d+)?)%\s*$

had a greedy `.*` between the module name and the trailing `\d+%`,
which ate all but the last digit of the percent. On lines like

    Wolfgang.Extensions.<X>                         100%

the regex captured percent=0 (the last "0" of "100"), reported the
module as failing the 90% threshold, and tanked the entire gate even
on 100%-covered code. First surfaced on DateTime-Extensions vNext —
PR #189 has the original fix.

Two changes to align with Stage 1 (Linux), whose awk-based parser is
correct:

- Anchor on `^(\S+)` to skip indented sub-class rows (Stage 1's
  `^[^ ]` does the same — assembly rows carry the aggregate
  percent, so nothing is lost).

- Drop the `.*`; let `\s+` separate the module from the final
  `\d+%` directly, so there is no greedy region to swallow digits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Every shippable src csproj across the fleet had `<AssemblyVersion>1.0.0</AssemblyVersion>`
hardcoded — last touched at v1.0.0 and never bumped. Released NuGet
packages from v1.1.0 onward have shipped with AssemblyVersion=1.0.0
even though the package <Version> bumped normally.

Drop the explicit AssemblyVersion line. .NET SDK derives AssemblyVersion,
FileVersion, and InformationalVersion from <Version> when they are not
specified, so all four track every <Version> bump automatically going
forward. They are not byte-identical — AssemblyVersion is normalized to
a 4-part System.Version, InformationalVersion can carry a +<git-sha>
under SourceLink — but they all reflect the current Version, which is
the point.

Mirrors DateTime-Extensions PR #184 (already merged to main).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the explicit <RepositoryUrl>https://github.com/Chris-Wolfgang/System.Mail-Extensions.git</RepositoryUrl>
field that the canonical CI3 metadata comment in Directory.Build.props
lists as a per-repo csproj field. The repository URL is now embedded in
the generated nupkg's nuspec, which SourceLink and the GitHub Packages
UI both surface.

Mirrors DateTime-Extensions PR #185 (already merged to main).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…4 fix)

The C4 fanout dropped <AssemblyVersion> on the rationale that the hardcoded
1.0.0 was 'stale' relative to released package versions, but that staleness
was the correct binding-stability behaviour for a library shipping a net462
TFM. SDK-deriving AssemblyVersion from <Version> changes the binding identity
on every minor/patch bump, breaking .NET Framework consumers without binding
redirects.
Addresses Copilot review feedback on the fix/restore-assemblyversion PR:
- Reword comment so it does not imply AssemblyVersion tracks NuGet major
  (it is a fixed binding-stability baseline, not derived from Version).
- Use regex-strip property function for FileVersion so prerelease
  <Version> values (e.g., 0.1.0-alpha) still produce a 4-part numeric
  AssemblyFileVersion (otherwise FileVersion fails the build).
- Remove pre-existing literal <FileVersion>1.0.0</FileVersion> where
  present (ETL repos) since MSBuild last-write semantics would
  otherwise override the property-function value.
Copilot AI review requested due to automatic review settings June 1, 2026 02:00

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 cuts v0.1.1 by folding a canonical maintenance round (CI/docs/metadata hardening and repo-template drift sync) together with an AssemblyVersion pin intended to preserve binding stability for .NET Framework consumers.

Changes:

  • Pins AssemblyVersion (binding-stability baseline) and derives prerelease-safe FileVersion; bumps library package version to 0.1.1.
  • Centralizes nullable enablement + analyzer/NuGet metadata defaults in Directory.Build.props, and adds Public API analyzer scaffolding files.
  • Expands CI/CD and docs automation (DocFX verification + deploy guards, coverage publishing, CodeQL security-extended, Stryker workflow, Dependabot for GitHub Actions), plus removes post-setup bootstrap scripts.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
Wolfgang.Extensions.IAsyncEnumerable.Example/Wolfgang.Extensions.IAsyncEnumerable.Example.csproj Removes per-project nullable setting in favor of centralized nullable config.
tests/Wolfgang.Extensions.Mail.Tests.Unit/Wolfgang.Extensions.Mail.Tests.Unit.csproj Removes per-project nullable setting in favor of centralized nullable config.
tests/.editorconfig Relaxes selected analyzer rules specifically for test code.
src/Wolfgang.Extensions.Mail/Wolfgang.Extensions.Mail.csproj Bumps version to 0.1.1 and pins AssemblyVersion + computed FileVersion; adds repository metadata.
src/Wolfgang.Extensions.Mail/PublicAPI.Shipped.txt Adds shipped public API baseline for PublicApiAnalyzers.
src/Wolfgang.Extensions.Mail/PublicAPI.Unshipped.txt Adds unshipped public API tracking scaffold.
scripts/Validate-DocsDeploy.sh Adds post-deploy gh-pages validation for DocFX output + versions.json integrity.
scripts/setup.ps1 Removes template setup bootstrap script.
scripts/Setup-Labels.ps1 Adds shebang and expands label set + repository parameter validation.
scripts/Setup-GitHubPages.ps1 Removes template GitHub Pages setup bootstrap script.
scripts/format.ps1 Makes formatting script resilient to being invoked from any repo subdirectory and updates guidance.
scripts/Fix-BranchRuleset.ps1 Adds helper to disable/rename existing rulesets and re-run branch ruleset setup.
scripts/build-pr.ps1 Improves tool install/update behavior and PATH handling; removes deprecated -UseBasicParsing.
docs/WORKFLOW_SECURITY.md Expands protected config list to include workflow YAML files.
docs/RELEASE-WORKFLOW-SETUP.md Adjusts troubleshooting guidance wording for Actions logs.
docs/README-FORMATTING.md Updates formatting docs to reflect LF + no-BOM PowerShell + SDK guidance.
docs/DOCFX-VERSION-PICKER.md Adds documentation describing the DocFX version picker design and operations.
Directory.Build.props Centralizes nullable enablement, analyzers, PublicApiAnalyzers package + file wiring, and NuGet metadata defaults.
CONTRIBUTING.md Updates contributor guidance, analyzer description, and build/test instructions.
CHANGELOG.md Adds Keep-a-Changelog structured changelog scaffold.
BannedSymbols.txt Replaces template placeholder with the actual project name.
.github/workflows/stryker.yaml Adds scheduled/manual mutation testing workflow (no-op if not configured).
.github/workflows/release.yaml Adds verify-docs-build gate, fixes job key duplication, and includes .snupkg in release assets.
.github/workflows/pr.yaml Hardens protected-config fetching, adds workload restore, strengthens coverage gating/parsing, and refines test discovery.
.github/workflows/docfx.yaml Publishes coverage into docs, adds versions.json preservation guard, and hardens gh-pages deploy logic.
.github/workflows/codeql.yaml Enables security-extended query pack and adds workload restore step.
.github/workflows/build-all-versions.yaml Improves solution detection and filters versions.json entries to built tags only.
.github/pull_request_template.md Adds guidance for linking maintenance-task issues for auto-closure/project updates.
.github/ISSUE_TEMPLATE/maintenance-task.yaml Adds maintenance-task issue form to support the maintenance framework.
.github/dependabot.yml Adds Dependabot updates for the github-actions ecosystem and adjusts labeling/groups.
.gitattributes Switches PowerShell scripts to LF (shebang-safe) and updates rationale.
.editorconfig Removes PS1 CRLF/BOM override and documents shebang requirements.

Comment thread CONTRIBUTING.md
Same shape as the other fleet release PRs (ETL-Abstractions#192,
ETL-FixedWidth#134, ETL-Test-Kit#112, Try-Pattern#166) — resolves
2 conflict files by taking main's (canonical) version:

- .github/workflows/docfx.yaml — vNext was behind on the canonical
  D8 inline-root-redirect, workflow_call-safe `env: GITHUB_REPOSITORY`
  derive, and hardened error handling in the existing versions.json
  fetch.
- docs/DOCFX-VERSION-PICKER.md — main's version documents the
  inlined-HTML approach; vNext's still described the deleted
  template file.

Plus Copilot's CONTRIBUTING.md L55 nit:

- CONTRIBUTING.md: section heading was "The 7 Analyzers" but
  Directory.Build.props now also references
  Microsoft.CodeAnalysis.PublicApiAnalyzers. Renamed to "The 8
  Analyzers" and added an entry that explains its opt-in semantics
  (package referenced unconditionally; analyzer only emits when
  PublicAPI.*.txt baseline files exist).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Chris-Wolfgang

Copy link
Copy Markdown
Owner Author

Split-out protected-files PR is now in flight (see the PR I just opened above). Once it's admin-bypass-merged to main, I'll merge origin/main back into vNext and the 7 protected-file deltas here will vanish — this PR can then merge via the normal merge button with full ruleset enforcement (review-thread resolution + all required checks) on the 22 non-protected files.

Chris-Wolfgang added a commit that referenced this pull request Jun 19, 2026
Extracts the protected-file deltas from vNext (Release v0.1.1 PR #119)
so that PR can merge through the standard ruleset rather than admin-
bypassing the entire 29-file diff (which would also waive
required_review_thread_resolution on every non-protected file).

Files in this PR (matching the `Detect .NET Projects` guard patterns):
- .editorconfig
- BannedSymbols.txt
- Directory.Build.props
- .github/workflows/codeql.yaml
- .github/workflows/pr.yaml
- .github/workflows/release.yaml
- .github/workflows/stryker.yaml

These carry the canonical CI/analyzer/banned-API updates folded into
v0.1.1 (C1 fleet template-drift sync, CI2 github-actions ecosystem
on dependabot, A1 PublicApiAnalyzers scaffolding, T3 Stryker
workflow, D6 versions preservation guard, D8 inline root redirect,
etc.). They are verbatim copies of vNext's content at the time of
extraction; no new edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.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.

2 participants