Skip to content
Open
Show file tree
Hide file tree
Changes from 96 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
d10c0f6
Re-sync unprotected template-tracked files to canonical (C1 drift)
Chris-Wolfgang May 22, 2026
5226672
Re-sync protected config + workflow files to canonical (C1 drift)
Chris-Wolfgang May 22, 2026
6ff23f5
Fill {{PROJECT_NAME}} placeholder in CONTRIBUTING.md (Wolfgang.Extens…
Chris-Wolfgang May 22, 2026
37824d0
Propagate setup.ps1 UTF-8/newline fix from canonical
Chris-Wolfgang May 22, 2026
99650af
Add canonical test/benchmark project config (Phase-0 files)
Chris-Wolfgang May 22, 2026
40a6d84
Drop tests/Directory.Build.props — hold test projects to the warning bar
Chris-Wolfgang May 22, 2026
0253b0e
Hoist <Nullable>enable</Nullable> to Directory.Build.props
Chris-Wolfgang May 22, 2026
fe4c091
Scope the nullable hoist so it cannot break legacy / F# projects
Chris-Wolfgang May 22, 2026
c896206
Enable CodeQL security-extended query pack (S1)
Chris-Wolfgang May 23, 2026
6ed29ba
Add Stryker mutation-testing workflow (T3)
Chris-Wolfgang May 23, 2026
ed8b063
Verify documentation builds before publishing release (D8)
Chris-Wolfgang May 23, 2026
5c704e3
Add github-actions ecosystem to Dependabot (CI2)
Chris-Wolfgang May 23, 2026
081c54f
Add CHANGELOG.md (D3)
Chris-Wolfgang May 23, 2026
c422fb2
Verify previous versions preserved in docfx versions.json (D6)
Chris-Wolfgang May 23, 2026
f850c2a
Scaffold PublicApiAnalyzers infrastructure (A1)
Chris-Wolfgang May 23, 2026
1f0d517
Canonical NuGet package metadata + SourceLink + symbol packages (CI3)
Chris-Wolfgang May 23, 2026
0c703e1
Publish code-coverage report to docs/coverage/ (T1)
Chris-Wolfgang May 23, 2026
d1e9200
Address PR review round 2 (canonical-protected)
Chris-Wolfgang May 23, 2026
c53b1f1
Address PR review round 2 (canonical-unprotected)
Chris-Wolfgang May 23, 2026
518bd9f
Address PR review round 2 (t3-stryker)
Chris-Wolfgang May 23, 2026
c06ba5b
Fold T3 (stryker mutation-testing workflow) into canonical-protected
Chris-Wolfgang May 23, 2026
ba11b85
Drop vestigial one-time setup scripts (post-bootstrap cleanup)
Chris-Wolfgang May 24, 2026
63c3ed8
Tighten <Nullable> condition to SDK-style C# projects only
Chris-Wolfgang May 24, 2026
e72eb23
Add SDK-aware explanatory comment to <Nullable> property
Chris-Wolfgang May 24, 2026
baf8041
Pin stryker.yaml's upload-artifact to v7 to match rest of fleet
Chris-Wolfgang May 24, 2026
e7a83a8
Drop -UseBasicParsing from Invoke-WebRequest in docfx.yaml
Chris-Wolfgang May 24, 2026
7baaa5c
Make ReportGenerator install idempotent in docfx.yaml T1 step
Chris-Wolfgang May 24, 2026
19475b0
Align .gitattributes *.ps1 with .editorconfig (LF, not CRLF)
Chris-Wolfgang May 25, 2026
a9ddd38
Detect .slnx solutions in build-all-versions.yaml
Chris-Wolfgang May 25, 2026
d0d21f3
Filter versions.json to tags whose docs were actually built
Chris-Wolfgang May 25, 2026
254800c
D6 preservation guard: only treat 404 as first deploy
Chris-Wolfgang May 25, 2026
a9fdd3d
Disable persisted credentials in stryker.yaml checkout
Chris-Wolfgang May 25, 2026
ed59686
Make dotnet-stryker install idempotent in stryker.yaml
Chris-Wolfgang May 25, 2026
ad87a83
Gate dotnet workload restore on workload-bearing TFM detection
Chris-Wolfgang May 25, 2026
8e1d0d9
release.yaml: explicit Out-File -Encoding utf8 + DocFX shell: pwsh
Chris-Wolfgang May 25, 2026
573c7d0
docfx.yaml T1 coverage: pass --settings coverlet.runsettings
Chris-Wolfgang May 25, 2026
d1431eb
Gate verify-docs-build on validate-release + pack-and-validate
Chris-Wolfgang May 25, 2026
39d4194
Gate gh-pages root cleanup on DEPLOY_AS_LATEST=true
Chris-Wolfgang May 25, 2026
97023b7
Drop -windows from workload-TFM detection regex
Chris-Wolfgang May 25, 2026
66e29ac
verify-docs-build: install full SDK set to match validate-release
Chris-Wolfgang May 25, 2026
8f163ea
D6 guard: skip on dry-runs (inputs.deploy_to_pages == false)
Chris-Wolfgang May 25, 2026
315da9d
Fix invalid PowerShell in docfx.yaml SemVer prerelease comparator
Chris-Wolfgang May 25, 2026
d1054f1
Protected-file guard: detect deletions too (--diff-filter=AMRCD)
Chris-Wolfgang May 25, 2026
01d2aa2
Exclude *.Tests.Integration.* from pr.yaml test-discovery loops
Chris-Wolfgang May 25, 2026
8397af7
Fail job when protected-config fetch/copy fails
Chris-Wolfgang May 25, 2026
4dd467b
Gitleaks fetch: abort on transient failure, fall back only on missing…
Chris-Wolfgang May 25, 2026
aa6afe3
verify-docs-build: gated dotnet workload restore before restore/build
Chris-Wolfgang May 25, 2026
c79c770
pr.yaml: drop duplicated "configuration files from main" header bullet
Chris-Wolfgang May 25, 2026
3368f7b
Stage 3 coverage gate: skip when no coverage files were produced
Chris-Wolfgang May 25, 2026
0bc8da7
Stage 2 coverage parse: accept extra columns + fail on zero matches
Chris-Wolfgang May 25, 2026
05dd691
dotnet test: add --no-build --no-restore in all stages
Chris-Wolfgang May 25, 2026
ebe0dc5
stryker.yaml: drop dead/broken configs<<EOF output
Chris-Wolfgang May 25, 2026
0231998
Remove duplicated NuGet metadata defaults from per-project csprojs
Chris-Wolfgang May 25, 2026
66d4aee
docfx.yaml: align D6 comment with the actual fetch source
Chris-Wolfgang May 25, 2026
928456d
Sync workload-TFM comment with regex (drop -windows mention)
Chris-Wolfgang May 25, 2026
4ce8294
docfx.yaml T1 coverage: pin to a single TFM (net10.0)
Chris-Wolfgang May 25, 2026
ce2bf42
pr.yaml: fail (not skip) when ./tests is missing in a repo with src/
Chris-Wolfgang May 25, 2026
913a40e
Repair pr.yaml after broken Stage 2 coverage-regex fan-out
Chris-Wolfgang May 25, 2026
f0c28ae
CONTRIBUTING.md: correct format.ps1 and README-FORMATTING.md paths
Chris-Wolfgang May 25, 2026
b055769
scripts/format.ps1: work from repo root + correct usage examples
Chris-Wolfgang May 25, 2026
fa90544
CONTRIBUTING.md: correct AsyncFixer description (ConfigureAwait is MA…
Chris-Wolfgang May 25, 2026
543bd60
Fix-BranchRuleset.ps1: normalize Repository before gh api calls
Chris-Wolfgang May 25, 2026
4db68a5
CONTRIBUTING.md: bump prerequisite SDK to 10.0 to match repo TFMs
Chris-Wolfgang May 25, 2026
d6af4cd
scripts/Validate-DocsDeploy.sh: rmdir mktemp path before worktree add
Chris-Wolfgang May 25, 2026
e702644
Setup-Labels.ps1: restore early -Repository format validation
Chris-Wolfgang May 25, 2026
1501536
build-all-versions.yaml: pipe to Out-Host, not Write-Host
Chris-Wolfgang May 25, 2026
970cf01
scripts/build-pr.ps1: drop -UseBasicParsing from Invoke-WebRequest
Chris-Wolfgang May 25, 2026
f61fa3d
Remove subtree TreatWarningsAsErrors=false overrides
Chris-Wolfgang May 25, 2026
71e8fec
pr.yaml: run protected-config copy loop in parent shell, not subshell
Chris-Wolfgang May 25, 2026
7dcfc36
Stage 2 coverage regex: use greedy match to capture LAST percent
Chris-Wolfgang May 25, 2026
7df8cd4
Repair pr.yaml after second \$'-token corruption of Stage 2 regex
Chris-Wolfgang May 25, 2026
72d9aff
Strip year-specific <Copyright> overrides from src csprojs
Chris-Wolfgang May 25, 2026
aeb33ad
Validate-DocsDeploy.sh: handle SSH remote URLs in REPO_NAME parsing
Chris-Wolfgang May 25, 2026
adfc479
build-pr.ps1: ensure .NET global-tools dir is on PATH after install
Chris-Wolfgang May 25, 2026
8e448bd
D6 preservation guard: fail when newly-generated versions.json is mis…
Chris-Wolfgang May 25, 2026
97161a9
release.yaml: attach .snupkg symbol packages alongside .nupkg
Chris-Wolfgang May 25, 2026
12e8816
docfx.yaml deploy: precise exit-code handling on diff/commit/push
Chris-Wolfgang May 25, 2026
42d6f91
stryker.yaml: run BOTH root and per-test-project configs
Chris-Wolfgang May 25, 2026
aea0539
Stage 1 (Linux) coverage parser: fail when 0 modules match
Chris-Wolfgang May 25, 2026
7acf162
pr.yaml trusted-config-fetch: three correctness fixes
Chris-Wolfgang May 25, 2026
d918a45
docfx.yaml deploy: clear versions/<dir> and versions/latest before copy
Chris-Wolfgang May 25, 2026
aef7a3f
docfx coverage: add --no-restore to dotnet test
Chris-Wolfgang May 25, 2026
f0b26f1
D6 guard: also skip when deploy_as_latest is false (rebuild mode)
Chris-Wolfgang May 25, 2026
a5bd43c
D6 guard: emit ::error:: via Write-Host so Actions parses the annotation
Chris-Wolfgang May 25, 2026
ede9c9c
Stage 1 coverage parser: accept decimal percents + floor before compare
Chris-Wolfgang May 25, 2026
9dd5ac2
scripts: repair Setup-Labels.ps1 param block + drop --paginate on rul…
Chris-Wolfgang May 26, 2026
edefc85
pr.yaml: fix Stage 2 coverage parser — greedy .* turned 100% into 0%
Chris-Wolfgang May 26, 2026
d7a84b7
C4: drop stale <AssemblyVersion> from src csproj(s)
Chris-Wolfgang May 26, 2026
09b85d9
CI1: add <RepositoryUrl> to src csproj(s)
Chris-Wolfgang May 26, 2026
b561d4e
Restore <AssemblyVersion>1.0.0.0</AssemblyVersion> + <FileVersion> (C…
Chris-Wolfgang May 28, 2026
6ccef7b
D8: add verify-docs-build job (canonical sync from repo-template#395)
Chris-Wolfgang May 28, 2026
323ef21
Refine AssemblyVersion comment + use prerelease-safe FileVersion
Chris-Wolfgang May 28, 2026
31110de
Merge remote-tracking branch 'origin/canonical-unprotected' into vNext
Chris-Wolfgang Jun 1, 2026
75e881e
Merge remote-tracking branch 'origin/protected/d8-verify-docs-build-f…
Chris-Wolfgang Jun 1, 2026
f1c2725
Merge remote-tracking branch 'origin/fix/restore-assemblyversion' int…
Chris-Wolfgang Jun 1, 2026
62cb614
v0.1.1 release prep: dup-fix + missing docs file + version bump
Chris-Wolfgang Jun 1, 2026
0000f11
Merge main into vNext for v0.1.1 release prep + CONTRIBUTING fix
Chris-Wolfgang Jun 19, 2026
11e2139
Merge branch 'main' into vNext
Chris-Wolfgang Jun 19, 2026
38acf82
Merge branch 'main' into vNext
Chris-Wolfgang Jun 28, 2026
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
13 changes: 6 additions & 7 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@ indent_size = 2
[*.{yml,yaml}]
indent_size = 2

# PowerShell files
# PowerShell uses CRLF to maintain compatibility with Windows and PowerShell conventions
# This overrides the global end_of_line = lf setting and aligns with .gitattributes line 14
[*.ps1]
indent_size = 4
end_of_line = crlf
charset = utf-8-bom
# PowerShell scripts inherit LF + UTF-8 (no BOM) + 4-space indent from
# the global [*] section above — no per-language override is needed.
# LF + no-BOM is required for the `#!/usr/bin/env pwsh` shebang (where
# present) on scripts under scripts/ to work on Linux/macOS — CR
# breaks the kernel's exec lookup, and a leading BOM prevents shebang
# recognition entirely.

# C# files
[*.cs]
Expand Down
19 changes: 14 additions & 5 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,20 @@
*.fsx text eol=lf

# Scripts
# PowerShell scripts: CRLF line endings (intentional override)
# Both .gitattributes and .editorconfig consistently configure PowerShell files
# to use CRLF (Windows-style) line endings for PowerShell convention compliance.
# See .editorconfig [*.ps1] section for the matching configuration.
*.ps1 text eol=crlf
# PowerShell scripts: enforce LF line endings in both the index AND
# the working tree (the explicit `eol=lf` overrides any user-level
# `core.autocrlf=true` setting that would otherwise convert to CRLF
# on checkout). BOM-free UTF-8 encoding is enforced separately by
# .editorconfig's global `charset = utf-8` — `.gitattributes` can
# normalize line endings (and control text/binary, diff, and merge
# behavior) but has no attribute for byte-order marks.
#
# LF is required for the `#!/usr/bin/env pwsh` shebang to work on
# Linux/macOS — the kernel parses CR as part of the interpreter name
# (looking for `pwsh\r`), and a UTF-8 BOM before `#!` would prevent
# shebang recognition entirely. Modern PowerShell 7+ handles LF on
# Windows transparently.
*.ps1 text eol=lf


# Build and configuration files
Expand Down
76 changes: 76 additions & 0 deletions .github/ISSUE_TEMPLATE/maintenance-task.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
name: "✨ Maintenance task"
description: "Track an actionable improvement under the Maintenance framework (security, performance, testing, cleanup, docs, API, or CI/CD)."
title: "[Maintenance] <category>: <short description>"
labels: [maintenance-task]
assignees: []
body:
- type: markdown
attributes:
value: |
## Maintenance framework sub-issue

This template creates a **`maintenance-task`** sub-issue under this repo's parent `Maintenance: <repo>` issue. The new issue will auto-appear in the cross-repo Maintenance project board (URL listed in the parent `Maintenance: <repo>` issue body).

- Pick exactly **one** category in the dropdown below. The corresponding `maintenance - <category>` label will need to be added manually after creation (issue forms don't yet support dynamic label addition).
- Fill in **Scope** (what's done & why), **Acceptance** (when do we close this?), and **Links** (PRs, scan output, related issues).
- If you're closing this issue via a PR, include `Fixes #<this-issue-number>` in the PR body so the auto-add workflow marks the project item as Done.

- type: dropdown
id: category
attributes:
label: Category
description: "Pick exactly one. After creation, also add the corresponding `maintenance - <category>` label."
options:
- "security — scans, finding fixes, dependency vulnerability audit"
- "performance — profile, benchmark, optimize, validate gains"
- "testing — coverage, integration/smoke/mutation tests, fixtures"
- "cleanup — refactor for reuse / quality / efficiency"
- "docs — XML doc coverage, README, CHANGELOG, samples"
- "API — public/internal surface audit, breaking-change vigilance"
- "CI/CD — Docker, CI workflow, build/publish pipeline"
validations:
required: true

- type: textarea
id: scope
attributes:
label: Scope
description: "What needs to be done? What's the motivation?"
placeholder: |
e.g.
- Profile the hot path in `Extractor.ExtractAsync` and identify the dominant allocations.
- Goal: reduce per-record allocations to enable streaming larger inputs.
validations:
required: true

- type: textarea
id: acceptance
attributes:
label: Acceptance criteria
description: "When do we close this issue? Concrete observable outcomes."
placeholder: |
e.g.
- Benchmark X shows <50% of current allocations.
- No regression in existing benchmark suite (>5%).
- Updated benchmark numbers committed.
validations:
required: true

- type: textarea
id: links
attributes:
label: Links
description: "Related PRs, scan output, prior issues, external references."
placeholder: |
- Related PR: #...
- Scan output: ...
- Related issue: #...
validations:
required: false

- type: markdown
attributes:
value: |
---

💡 **Tip for agents (Copilot etc.):** When opening a maintenance-task sub-issue, use this template and pick the matching category. After creation, add the `maintenance - <category>` label manually. See `.github/copilot-instructions.md` for the full Maintenance framework convention.
14 changes: 13 additions & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,20 @@ updates:
open-pull-requests-limit: 10
labels:
- "dependencies"
- "dotnet"
groups:
dotnet-dependencies:
patterns:
- "*"

# Keep third-party GitHub Actions pinned in workflows up to date.
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
labels:
- "dependencies"
groups:
github-actions:
patterns:
- "*"
12 changes: 12 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,18 @@

Fixes/Complete # (issue)

<!--
If this PR addresses a Maintenance framework sub-issue, link it explicitly so the
project board auto-marks the item as Done on merge:
Fixes #<maintenance-task-issue-number>
The Maintenance framework tracks ongoing improvement work (security, performance,
testing, cleanup, docs, API, CI/CD) — see the parent `Maintenance: <repo>` issue
for details.
-->


## Type of change

Please delete options that are not relevant.
Expand Down
27 changes: 20 additions & 7 deletions .github/workflows/build-all-versions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -119,20 +119,20 @@ jobs:
try {
# Attempt dotnet restore + build; failures are non-fatal because
# DocFX can still extract metadata from source files.
$slnFile = Get-ChildItem -Filter '*.sln' -ErrorAction SilentlyContinue |
$slnFile = Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -in '.sln','.slnx' } |
Select-Object -First 1
if ($slnFile) {
Write-Host "Restoring $($slnFile.Name)..."
dotnet restore $slnFile.FullName 2>&1 | Write-Host
dotnet restore $slnFile.FullName 2>&1 | Out-Host
Write-Host "Building $($slnFile.Name)..."
dotnet build $slnFile.FullName --configuration Release --no-restore 2>&1 | Write-Host
dotnet build $slnFile.FullName --configuration Release --no-restore 2>&1 | Out-Host
}

Write-Host "Running docfx metadata..."
docfx metadata docfx_project/docfx.json 2>&1 | Write-Host
docfx metadata docfx_project/docfx.json 2>&1 | Out-Host

Write-Host "Running docfx build..."
docfx build docfx_project/docfx.json 2>&1 | Write-Host
docfx build docfx_project/docfx.json 2>&1 | Out-Host

if (Test-Path 'docfx_project/_site') {
$dest = Join-Path $outDir 'versions' $version
Expand Down Expand Up @@ -207,7 +207,7 @@ jobs:

Push-Location $latestWorkDir
try {
$slnFile = Get-ChildItem -Filter '*.sln' -ErrorAction SilentlyContinue |
$slnFile = Get-ChildItem -File -ErrorAction SilentlyContinue | Where-Object { $_.Extension -in '.sln','.slnx' } |
Select-Object -First 1
if ($slnFile) {
Write-Host "Restoring $($slnFile.Name)..."
Expand Down Expand Up @@ -285,9 +285,22 @@ jobs:
Sort-Object -Property Major, Minor, Patch, Stable -Descending |
Select-Object -ExpandProperty Tag

# Only emit version-picker entries for tags whose docs were actually
# built and copied under $outDir/versions/<tag>/. Skipped tags (worktree
# add failed, DocFX produced no _site, etc.) would otherwise appear in
# versions.json as links to 404s on gh-pages.
$versionsDir = Join-Path $outDir 'versions'
$builtTags = if (Test-Path $versionsDir) {
Get-ChildItem -Path $versionsDir -Directory | Select-Object -ExpandProperty Name
} else { @() }

[array]$versions = @([PSCustomObject]@{ version = 'latest'; url = "${base}versions/latest/" })
foreach ($t in $orderedTags) {
$versions += [PSCustomObject]@{ version = $t; url = "${base}versions/$t/" }
if ($builtTags -contains $t) {
$versions += [PSCustomObject]@{ version = $t; url = "${base}versions/$t/" }
} else {
Write-Host "::notice::Skipping versions.json entry for $t — no built docs under versions/$t/"
}
}

$versionsJson = ConvertTo-Json -InputObject $versions -Depth 3
Expand Down
31 changes: 31 additions & 0 deletions .github/workflows/codeql.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,44 @@ jobs:
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# security-extended adds the broader security query pack on top of the
# default queries (more rules, slightly longer scans).
queries: security-extended

- name: Setup .NET
if: steps.check-csharp.outputs.has-csharp == 'true'
uses: actions/setup-dotnet@v5
with:
dotnet-version: '10.0.x'

- name: Restore .NET workloads
if: steps.check-csharp.outputs.has-csharp == 'true'
shell: pwsh
run: |
# Skip entirely if no csproj declares a workload-bearing TFM (android/ios/
# maccatalyst/maui/tvos/tizen/browser) — netX.Y-windows TFMs use
# SDK-bundled projection assemblies, not the workload installer, so
# they're intentionally excluded. Saves ~5-15s on pure-library
# repos and removes a network-dependent failure mode.
$hasWorkloadTfm = @(Get-ChildItem -Recurse -Filter *.csproj |
Select-String -Pattern 'net\d+\.\d+-(android|ios|maccatalyst|maui|tvos|tizen|browser)' -List).Count -gt 0
if (-not $hasWorkloadTfm) {
Write-Host "No workload-bearing TFMs — skipping dotnet workload restore"
exit 0
}
$solution = Get-ChildItem -Path . -Recurse -Depth 2 -Include "*.sln", "*.slnx" | Select-Object -First 1
if ($solution) {
Write-Host "Restoring workloads for $($solution.FullName)"
dotnet workload restore "$($solution.FullName)"
} else {
Write-Host "No solution found; restoring workloads for all projects"
dotnet workload restore
}
if ($LASTEXITCODE -ne 0) {
Write-Error "dotnet workload restore failed with exit code $LASTEXITCODE"
exit $LASTEXITCODE
}

- name: Build for CodeQL Analysis
id: build
if: steps.check-csharp.outputs.has-csharp == 'true'
Expand Down
Loading
Loading