From 88db9e6e60589e8d8d06ccc7483302307f9ab763 Mon Sep 17 00:00:00 2001 From: austinbhale Date: Sat, 25 Jul 2026 17:06:14 -0700 Subject: [PATCH 1/5] ci: publish a nakamir-suffixed package built against local sk_renderer The build had no way to produce the configuration Nakamir actually consumes. sk_renderer is auto-detected as a sibling of the repo root, which sits outside the workspace, so CI checks it out inside and moves it into place. Its ref is an input because only the consuming repo knows which pair of revisions is valid. Set-Version gains a suffix that extends the prerelease label instead of replacing it, keeping the result ordered after the upstream build it came from. The header macros are numeric and cannot carry it, so Get-Version now defers to the csproj whenever it extends the header version, which keeps the .nupkg path in step with what dotnet pack emits. Both stay byte-identical without a suffix. The push target is now a parameter so the feed is a caller decision. --- .github/workflows/build.yml | 79 ++++++++++++++++++++++++++++++++++--- tools/Build-Nuget.ps1 | 3 +- tools/Get-Version.ps1 | 12 ++++++ tools/Set-Version.ps1 | 8 +++- 4 files changed, 95 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a667d3929..9dfd24d5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -38,6 +38,21 @@ on: type: string required: false default: 'preview' + suffix: + description: 'Version suffix identifying this distribution, e.g. nakamir.0' + type: string + required: false + default: '' + skRendererRef: + description: 'sk_renderer ref to build against. Empty uses the CPM-pinned release.' + type: string + required: false + default: '' + nugetSource: + description: 'NuGet feed to push to' + type: string + required: false + default: 'https://api.nuget.org/v3/index.json' workflow_call: inputs: branch: @@ -76,6 +91,21 @@ on: type: string required: false default: 'preview' + suffix: + description: 'Version suffix identifying this distribution, e.g. nakamir.0' + type: string + required: false + default: '' + skRendererRef: + description: 'sk_renderer ref to build against. Empty uses the CPM-pinned release.' + type: string + required: false + default: '' + nugetSource: + description: 'NuGet feed to push to' + type: string + required: false + default: 'https://api.nuget.org/v3/index.json' secrets: NUGET_KEY: required: true @@ -99,6 +129,19 @@ jobs: ref: ${{ inputs.branch }} - uses: lukka/get-cmake@v4.3.3 + - name: Check out sk_renderer + if: inputs.skRendererRef != '' + uses: actions/checkout@v4 + with: + repository: Nakamir-Code/sk_renderer + ref: ${{ inputs.skRendererRef }} + path: .sk_renderer + + - name: Move sk_renderer beside the repo + if: inputs.skRendererRef != '' + shell: pwsh + run: Move-Item .sk_renderer (Join-Path (Split-Path $env:GITHUB_WORKSPACE -Parent) 'sk_renderer') + - name: Get Cache uses: actions/cache@v4 with: @@ -108,7 +151,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' - name: Build Native Win32 x64 run: | @@ -144,6 +187,19 @@ jobs: ref: ${{ inputs.branch }} - uses: lukka/get-cmake@v4.3.3 + - name: Check out sk_renderer + if: inputs.skRendererRef != '' + uses: actions/checkout@v4 + with: + repository: Nakamir-Code/sk_renderer + ref: ${{ inputs.skRendererRef }} + path: .sk_renderer + + - name: Move sk_renderer beside the repo + if: inputs.skRendererRef != '' + shell: pwsh + run: Move-Item .sk_renderer (Join-Path (Split-Path $env:GITHUB_WORKSPACE -Parent) 'sk_renderer') + - name: Get Cache uses: actions/cache@v4 with: @@ -178,7 +234,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' - name: Build Native Linux x64 run: | @@ -236,6 +292,19 @@ jobs: ref: ${{ inputs.branch }} - uses: lukka/get-cmake@v4.3.3 + - name: Check out sk_renderer + if: inputs.skRendererRef != '' + uses: actions/checkout@v4 + with: + repository: Nakamir-Code/sk_renderer + ref: ${{ inputs.skRendererRef }} + path: .sk_renderer + + - name: Move sk_renderer beside the repo + if: inputs.skRendererRef != '' + shell: pwsh + run: Move-Item .sk_renderer (Join-Path (Split-Path $env:GITHUB_WORKSPACE -Parent) 'sk_renderer') + - name: Get Cache uses: actions/cache@v4 with: @@ -245,7 +314,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' - name: Build Native macOS ARM64 run: | @@ -295,12 +364,12 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' - name: Build Package and Upload if: inputs.upload == true shell: pwsh - run: ./tools/Build-Nuget.ps1 -nobuild -notest -upload -key ${{ secrets.NUGET_KEY }} + run: ./tools/Build-Nuget.ps1 -nobuild -notest -upload -key ${{ secrets.NUGET_KEY }} -source '${{ inputs.nugetSource }}' - name: Build Package without Upload if: inputs.upload == false diff --git a/tools/Build-Nuget.ps1 b/tools/Build-Nuget.ps1 index 47b57b505..f0eb1b36f 100755 --- a/tools/Build-Nuget.ps1 +++ b/tools/Build-Nuget.ps1 @@ -3,6 +3,7 @@ param( [switch]$noTest = $false, [switch]$noBuild = $false, [string]$key = '', + [string]$source = 'https://api.nuget.org/v3/index.json', [string]$saveKey = '', [switch]$noLinux = $false, [switch]$noWin32 = $false, @@ -220,7 +221,7 @@ if ($upload) { if ($key -ne '') { $key = $key.Trim() $nupkgPath = Join-Path $PSScriptRoot ".." "bin" "StereoKit.$($version.str).nupkg" - & dotnet nuget push $nupkgPath -k $key -s https://api.nuget.org/v3/index.json + & dotnet nuget push $nupkgPath -k $key -s $source } else { Write-Host 'No key, cancelling upload' } diff --git a/tools/Get-Version.ps1 b/tools/Get-Version.ps1 index c395e6c2a..2a07fa7a4 100755 --- a/tools/Get-Version.ps1 +++ b/tools/Get-Version.ps1 @@ -14,6 +14,18 @@ if ($pre -ne 0) { $str = "$str-preview.$pre" } +$csprojPath = "$PSScriptRoot\..\StereoKit\StereoKit.csproj" +if (Test-Path $csprojPath) { + $csprojData = Get-Content -Path $csprojPath -Raw + if ($csprojData -match '(?[^<]+)') { + $full = $Matches.ver.Trim() + if (($full.Length -gt $str.Length) -and $full.StartsWith($str) -and + (@('.', '-') -contains $full.Substring($str.Length, 1))) { + $str = $full + } + } +} + return @{ 'str' = $str; 'major' = $major; diff --git a/tools/Set-Version.ps1 b/tools/Set-Version.ps1 index 98c414983..a05310e99 100755 --- a/tools/Set-Version.ps1 +++ b/tools/Set-Version.ps1 @@ -2,7 +2,8 @@ param( [int]$major, [int]$minor, [int]$patch, - [int]$pre = 0 + [int]$pre = 0, + [string]$suffix = '' ) $version = "$major.$minor.$patch" @@ -10,6 +11,11 @@ $versionFull = $version if ($pre -ne 0) { $versionFull = "$version-preview.$pre" } +# Distribution suffix for forks, e.g. 'nakamir.0'. +if ($suffix -ne '') { + $separator = if ($pre -ne 0) { '.' } else { '-' } + $versionFull = "$versionFull$separator$suffix" +} # This file is the source of truth for the version. It may even be the source # of the version provided as an argument. Overwriting it may be redundant, but From f7657110bbdb86fa81413233e3a158838cc892d7 Mon Sep 17 00:00:00 2001 From: austinbhale Date: Sat, 25 Jul 2026 17:14:28 -0700 Subject: [PATCH 2/5] ci: let SourceLink stamp the repository into the package GitHub Packages rejects a push whose nuspec carries no repository element. SourceLink is already referenced, so publishing its resolved URL fills that in without hardcoding an owner, which keeps forks and upstream merges correct. It also records the commit, tying a published package to the revision it came from. --- StereoKit/StereoKit.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/StereoKit/StereoKit.csproj b/StereoKit/StereoKit.csproj index c739dbc60..2562cdf60 100644 --- a/StereoKit/StereoKit.csproj +++ b/StereoKit/StereoKit.csproj @@ -27,6 +27,7 @@ MIT OpenXR C# AR VR MR XR MixedReality HoloLens false + true true From 044ff2e7a910be710c7723e6826b62c1bcb74dfd Mon Sep 17 00:00:00 2001 From: austinbhale Date: Sat, 25 Jul 2026 17:28:06 -0700 Subject: [PATCH 3/5] ci: trim publish changes to the minimum upstream surface The three native jobs never pack, so passing -suffix to their Set-Version calls had no effect. The workflow_call copies of suffix and skRendererRef are never supplied by nightly_build or release_build; nugetSource stays declared there so its upload target does not resolve to an empty string. --- .github/workflows/build.yml | 16 +++------------- tools/Get-Version.ps1 | 13 +++---------- tools/Set-Version.ps1 | 3 +-- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9dfd24d5e..53f8f97ec 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,16 +91,6 @@ on: type: string required: false default: 'preview' - suffix: - description: 'Version suffix identifying this distribution, e.g. nakamir.0' - type: string - required: false - default: '' - skRendererRef: - description: 'sk_renderer ref to build against. Empty uses the CPM-pinned release.' - type: string - required: false - default: '' nugetSource: description: 'NuGet feed to push to' type: string @@ -151,7 +141,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} - name: Build Native Win32 x64 run: | @@ -234,7 +224,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} - name: Build Native Linux x64 run: | @@ -314,7 +304,7 @@ jobs: - name: Set Version shell: pwsh - run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} -suffix '${{inputs.suffix}}' + run: ./tools/Set-Version.ps1 -major ${{inputs.major}} -minor ${{inputs.minor}} -patch ${{inputs.patch}} -pre ${{inputs.pre}} -preName ${{inputs.preName}} - name: Build Native macOS ARM64 run: | diff --git a/tools/Get-Version.ps1 b/tools/Get-Version.ps1 index 2a07fa7a4..12e9e6998 100755 --- a/tools/Get-Version.ps1 +++ b/tools/Get-Version.ps1 @@ -14,16 +14,9 @@ if ($pre -ne 0) { $str = "$str-preview.$pre" } -$csprojPath = "$PSScriptRoot\..\StereoKit\StereoKit.csproj" -if (Test-Path $csprojPath) { - $csprojData = Get-Content -Path $csprojPath -Raw - if ($csprojData -match '(?[^<]+)') { - $full = $Matches.ver.Trim() - if (($full.Length -gt $str.Length) -and $full.StartsWith($str) -and - (@('.', '-') -contains $full.Substring($str.Length, 1))) { - $str = $full - } - } +# A distribution suffix lives only in the csproj, and extends this version. +if ((Get-Content -Path "$PSScriptRoot\..\StereoKit\StereoKit.csproj" -Raw -ErrorAction SilentlyContinue) -match "(?$([regex]::Escape($str))[-.][^<]+)") { + $str = $Matches.ver } return @{ diff --git a/tools/Set-Version.ps1 b/tools/Set-Version.ps1 index a05310e99..760bc85b3 100755 --- a/tools/Set-Version.ps1 +++ b/tools/Set-Version.ps1 @@ -13,8 +13,7 @@ if ($pre -ne 0) { } # Distribution suffix for forks, e.g. 'nakamir.0'. if ($suffix -ne '') { - $separator = if ($pre -ne 0) { '.' } else { '-' } - $versionFull = "$versionFull$separator$suffix" + $versionFull = "$versionFull$(if ($pre -ne 0) { '.' } else { '-' })$suffix" } # This file is the source of truth for the version. It may even be the source From cab69588905cb38c96bdacb1385bd11acc73bd57 Mon Sep 17 00:00:00 2001 From: austinbhale Date: Sat, 25 Jul 2026 17:43:11 -0700 Subject: [PATCH 4/5] ci: fall back to GITHUB_TOKEN when no NuGet key is configured Publishing to a GitHub Packages feed in the workflow's own org needs no PAT. Callers that set NUGET_KEY, such as nightly_build and release_build pushing to nuget.org, are unaffected. --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 53f8f97ec..4bbef50df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -103,6 +103,7 @@ on: permissions: contents: write actions: write + packages: write jobs: @@ -359,7 +360,7 @@ jobs: - name: Build Package and Upload if: inputs.upload == true shell: pwsh - run: ./tools/Build-Nuget.ps1 -nobuild -notest -upload -key ${{ secrets.NUGET_KEY }} -source '${{ inputs.nugetSource }}' + run: ./tools/Build-Nuget.ps1 -nobuild -notest -upload -key ${{ secrets.NUGET_KEY || secrets.GITHUB_TOKEN }} -source '${{ inputs.nugetSource }}' - name: Build Package without Upload if: inputs.upload == false From 2ca7f0a8bbad3981b502cea08d189aa1de082e32 Mon Sep 17 00:00:00 2001 From: austinbhale Date: Sat, 25 Jul 2026 18:19:25 -0700 Subject: [PATCH 5/5] fix: keep the distribution suffix through Build-Nuget's version restamp Build-Nuget re-stamps the version from the numeric components alone, which dropped the suffix the workflow had just written and left the computed nupkg path pointing at a file pack never produced. --- tools/Build-Nuget.ps1 | 2 +- tools/Get-Version.ps1 | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/Build-Nuget.ps1 b/tools/Build-Nuget.ps1 index f0eb1b36f..415ea2985 100755 --- a/tools/Build-Nuget.ps1 +++ b/tools/Build-Nuget.ps1 @@ -62,7 +62,7 @@ Push-Location -Path (Join-Path $PSScriptRoot "..") $version = & (Join-Path $PSScriptRoot "Get-Version.ps1") # Ensure all versions match the source of truth -& (Join-Path $PSScriptRoot "Set-Version.ps1") -major $version.major -minor $version.minor -patch $version.patch -pre $version.pre +& (Join-Path $PSScriptRoot "Set-Version.ps1") -major $version.major -minor $version.minor -patch $version.patch -pre $version.pre -suffix $version.suffix # Notify of build, and output the version Write-Host @" diff --git a/tools/Get-Version.ps1 b/tools/Get-Version.ps1 index 12e9e6998..39ed5418e 100755 --- a/tools/Get-Version.ps1 +++ b/tools/Get-Version.ps1 @@ -15,12 +15,15 @@ if ($pre -ne 0) { } # A distribution suffix lives only in the csproj, and extends this version. +$suffix = '' if ((Get-Content -Path "$PSScriptRoot\..\StereoKit\StereoKit.csproj" -Raw -ErrorAction SilentlyContinue) -match "(?$([regex]::Escape($str))[-.][^<]+)") { - $str = $Matches.ver + $suffix = $Matches.ver.Substring($str.Length + 1) + $str = $Matches.ver } return @{ 'str' = $str; + 'suffix' = $suffix; 'major' = $major; 'minor' = $minor; 'patch' = $patch;