Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
671 changes: 415 additions & 256 deletions .editorconfig

Large diffs are not rendered by default.

143 changes: 134 additions & 9 deletions .github/workflows/docfx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,84 @@ jobs:
# Sorting descending by Stable places stable (1) before prerelease (0) of the same version.
$stable = if ([string]::IsNullOrEmpty($Matches['prerelease'])) { 1 } else { 0 }
[PSCustomObject]@{
Tag = $t
Major = [int]$Matches['major']
Minor = [int]$Matches['minor']
Patch = [int]$Matches['patch']
Stable = $stable
Tag = $t
Major = [int]$Matches['major']
Minor = [int]$Matches['minor']
Patch = [int]$Matches['patch']
Stable = $stable
PreRelease = $Matches['prerelease']
}
}
}

# Sort descending by SemVer components so newest stable version comes first
$orderedTags = $taggedVersions |
Sort-Object -Property Major, Minor, Patch, Stable -Descending |
Select-Object -ExpandProperty Tag
# Sort descending by full SemVer precedence (Major, Minor, Patch, Stable, PreRelease)
# Convert to a mutable list so we can use a custom comparison for proper SemVer prerelease ordering.
$tagList = [System.Collections.Generic.List[object]]::new()
foreach ($item in $taggedVersions) {
[void]$tagList.Add($item)
}

$comparison = [System.Comparison[object]]{
param($a, $b)

# Compare Major, Minor, Patch (descending)
if ($a.Major -ne $b.Major) { return [Math]::Sign($b.Major - $a.Major) }
if ($a.Minor -ne $b.Minor) { return [Math]::Sign($b.Minor - $a.Minor) }
if ($a.Patch -ne $b.Patch) { return [Math]::Sign($b.Patch - $a.Patch) }

# Compare Stable flag (descending: stable=1 > prerelease=0)
if ($a.Stable -ne $b.Stable) { return [Math]::Sign($b.Stable - $a.Stable) }

# At this point, Major/Minor/Patch/Stable are equal.
# If both are stable (no prerelease), they are equal for our purposes.
$aPre = [string]$a.PreRelease
$bPre = [string]$b.PreRelease

if ([string]::IsNullOrEmpty($aPre) -and [string]::IsNullOrEmpty($bPre)) { return 0 }

# Both should be prereleases when Stable is 0, but handle any unexpected cases gracefully.
if ([string]::IsNullOrEmpty($aPre) -and -not [string]::IsNullOrEmpty($bPre)) { return -1 }
if (-not [string]::IsNullOrEmpty($aPre) -and [string]::IsNullOrEmpty($bPre)) { return 1 }

$aIds = $aPre -split '\.'
$bIds = $bPre -split '\.'
$maxLen = [Math]::Max($aIds.Length, $bIds.Length)

for ($i = 0; $i -lt $maxLen; $i++) {
if ($i -ge $aIds.Length) { return -1 } # a has fewer identifiers -> lower precedence
if ($i -ge $bIds.Length) { return 1 } # b has fewer identifiers -> lower precedence

$aId = $aIds[$i]
$bId = $bIds[$i]

$aIsNum = [int]::TryParse($aId, [ref]([int]$null))
$bIsNum = [int]::TryParse($bId, [ref]([int]$null))

if ($aIsNum -and $bIsNum) {
$aVal = [int]$aId
$bVal = [int]$bId
if ($aVal -ne $bVal) { return [Math]::Sign($bVal - $aVal) }
}
elseif ($aIsNum -and -not $bIsNum) {
# Numeric identifiers have lower precedence than non-numeric.
return 1
}
elseif (-not $aIsNum -and $bIsNum) {
return -1
}
else {
$cmp = [string]::CompareOrdinal($aId, $bId)
if ($cmp -ne 0) { return -$cmp }
}
}

# All identifiers equal
return 0
}

$tagList.Sort($comparison)
# We implemented comparison for descending SemVer order directly in the comparison.
$orderedTags = $tagList | Select-Object -ExpandProperty Tag

# Build the base path for this GitHub Pages project site: /<repo-name>/
# GITHUB_REPOSITORY is "owner/repo"; we need just the repo name.
Expand All @@ -155,6 +220,66 @@ jobs:
Set-Content -Path 'docfx_project/_site/versions.json' -Encoding utf8NoBOM
Write-Host "Generated versions.json with $($versions.Count) version(s): $($versions | ForEach-Object { $_.version })"

- name: Clean up stale root files from gh-pages
# Before deploying the latest docs to the site root, remove any pre-existing
# root-level files and folders from the gh-pages branch (except the versions/
# directory, CNAME, and .nojekyll) so that stale DocFX assets from a previous
# build do not linger on the live site.
# The versions/ folder is preserved so that all versioned docs remain accessible
# while the root is refreshed with the new build.
if: inputs.deploy_to_pages != false && inputs.deploy_as_latest != false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: pwsh
run: |
$branchExists = git ls-remote --heads origin gh-pages
if (-not $branchExists) {
Write-Host "ℹ️ gh-pages branch does not exist yet – skipping stale-file cleanup."
exit 0
}

git config --global user.email "github-actions[bot]@users.noreply.github.com"
git config --global user.name "github-actions[bot]"
git remote set-url origin "https://x-access-token:$($env:GITHUB_TOKEN)@github.com/$($env:GITHUB_REPOSITORY).git"

git fetch origin gh-pages
# Create a local tracking branch only if it does not already exist
git show-ref --verify --quiet refs/heads/gh-pages
if ($LASTEXITCODE -ne 0) {
git branch gh-pages origin/gh-pages
}

$WORK_DIR = Join-Path $env:RUNNER_TEMP 'gh-pages-clean'
# Remove a leftover worktree from a previous failed run, if any
git worktree remove "$WORK_DIR" --force 2>&1 | Out-Null
if (Test-Path $WORK_DIR) { Remove-Item $WORK_DIR -Recurse -Force }
git worktree add "$WORK_DIR" gh-pages

# Remove all root-level items EXCEPT:
# .git – Git metadata (worktree pointer file)
# CNAME – Custom domain config (if present)
# .nojekyll – Tells GitHub Pages not to run Jekyll
# versions/ – All versioned docs (v1.0.0/, latest/, etc.)
Get-ChildItem -Path $WORK_DIR -Force | Where-Object {
$_.Name -ne '.git' -and
$_.Name -ne 'CNAME' -and
$_.Name -ne '.nojekyll' -and
$_.Name -ne 'versions'
} | Remove-Item -Recurse -Force

git -C "$WORK_DIR" add -A
git -C "$WORK_DIR" diff --cached --quiet
if ($LASTEXITCODE -ne 0) {
git -C "$WORK_DIR" commit `
-m "chore: clean up stale root DocFX assets before redeploy [skip ci]"
git -C "$WORK_DIR" push origin HEAD:gh-pages
Write-Host "✅ Stale root files removed from gh-pages."
} else {
Write-Host "ℹ️ No stale files found in gh-pages root – nothing to clean."
}

git worktree remove "$WORK_DIR" --force

- name: Compute destination directory
# Determines the versioned subfolder name for the docs deployment (e.g. /v1.2.3/).
# Uses the explicit 'version' input when provided; otherwise falls back to
Expand Down
Loading
Loading