Merge pull request #64 from ntoskrnl7/feature/chrono-format-ranges-co… #133
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
| name: Package | |
| on: | |
| pull_request: | |
| branches: [ main ] | |
| paths: | |
| - '.github/workflows/package.yml' | |
| - 'nuget/**' | |
| - 'scripts/nuget/**' | |
| - 'CMakeLists.txt' | |
| - 'LICENSE' | |
| - 'README.md' | |
| - 'build.bat' | |
| - 'build_all.bat' | |
| - 'cmake/**' | |
| - 'docs/**' | |
| - 'include/**' | |
| - 'src/**' | |
| - 'test/**' | |
| push: | |
| branches: [ main ] | |
| tags: | |
| - 'v*' | |
| paths: | |
| - '.github/workflows/package.yml' | |
| - 'nuget/**' | |
| - 'scripts/nuget/**' | |
| - 'CMakeLists.txt' | |
| - 'LICENSE' | |
| - 'README.md' | |
| - 'build.bat' | |
| - 'build_all.bat' | |
| - 'cmake/**' | |
| - 'docs/**' | |
| - 'include/**' | |
| - 'src/**' | |
| - 'test/**' | |
| workflow_dispatch: | |
| inputs: | |
| package_version: | |
| description: Optional package version override | |
| required: false | |
| type: string | |
| publish: | |
| description: Publish the generated package to nuget.org | |
| required: true | |
| type: boolean | |
| default: false | |
| github_release: | |
| description: Upload release assets to GitHub Releases | |
| required: true | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| env: | |
| CRTSYS_WINDOWS_SDK_VERSION: 10.0.22621.0 | |
| jobs: | |
| version: | |
| name: Resolve package version | |
| runs-on: windows-2022 | |
| outputs: | |
| package_version: ${{ steps.version.outputs.package_version }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Resolve package version | |
| id: version | |
| shell: pwsh | |
| run: | | |
| $version = '${{ inputs.package_version }}' | |
| if ([string]::IsNullOrWhiteSpace($version)) { | |
| $version = ./scripts/nuget/Get-CrtSysVersion.ps1 | |
| } | |
| if ($env:GITHUB_REF_TYPE -eq 'tag') { | |
| if ($env:GITHUB_REF_NAME -notmatch '^v(.+)$') { | |
| throw "Release tag must use v<version> format." | |
| } | |
| $tagVersion = $Matches[1] | |
| if ($version -ne $tagVersion) { | |
| throw "Package version '$version' does not match tag version '$tagVersion'." | |
| } | |
| } | |
| "package_version=$version" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| Write-Host "Package version: $version" | |
| build-libs: | |
| name: Build NuGet libs ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: version | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x86, x64, ARM, ARM64] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| runner: windows-2025-vs2026 | |
| windows_sdk: 10.0.26100.0 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Ensure WDK | |
| if: ${{ matrix.toolset == 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' | |
| - name: Ensure WDK for x86 | |
| if: ${{ matrix.arch == 'x86' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ env.CRTSYS_WINDOWS_SDK_VERSION }}' -RequiredPlatforms x86 | |
| - name: Ensure WDK for ARM32 | |
| if: ${{ matrix.arch == 'ARM' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM | |
| - name: Ensure WDK for ARM64 old toolsets | |
| if: ${{ matrix.arch == 'ARM64' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM64 | |
| - name: Build prebuilt libraries | |
| shell: pwsh | |
| run: | | |
| $windowsSdkVersion = '${{ matrix.windows_sdk }}' | |
| $wdkVersion = '' | |
| if ('${{ matrix.toolset }}' -eq 'v145' -and '${{ matrix.arch }}' -eq 'x86') { | |
| $wdkVersion = '${{ env.CRTSYS_WINDOWS_SDK_VERSION }}' | |
| } | |
| $parameters = @{ | |
| Toolset = '${{ matrix.toolset }}' | |
| Architecture = '${{ matrix.arch }}' | |
| Configuration = '${{ matrix.config }}' | |
| WindowsSdkVersion = $windowsSdkVersion | |
| } | |
| if (-not [string]::IsNullOrWhiteSpace($wdkVersion)) { | |
| $parameters.WdkVersion = $wdkVersion | |
| } | |
| ./scripts/nuget/Build-CrtSysNuGetLibs.ps1 @parameters | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: crtsys-nuget-libs-${{ matrix.toolset }}-${{ matrix.arch }}-${{ matrix.config }} | |
| path: artifacts/nuget-staging/lib/native/${{ matrix.toolset }}/${{ matrix.arch }}/${{ matrix.config }} | |
| if-no-files-found: error | |
| pack: | |
| name: Pack NuGet | |
| needs: [version, build-libs] | |
| runs-on: windows-2022 | |
| outputs: | |
| package_version: ${{ steps.version.outputs.package_version }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Set package version | |
| id: version | |
| shell: pwsh | |
| run: | | |
| "package_version=${{ needs.version.outputs.package_version }}" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - uses: NuGet/setup-nuget@v2 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| pattern: crtsys-nuget-libs-* | |
| path: artifacts/downloaded-libs | |
| - name: Stage downloaded prebuilt libraries | |
| shell: pwsh | |
| run: | | |
| $downloadRoot = Resolve-Path artifacts/downloaded-libs | |
| foreach ($artifact in Get-ChildItem -Path $downloadRoot -Directory) { | |
| if ($artifact.Name -notmatch '^crtsys-nuget-libs-(v[0-9]+)-(.+)-(Debug|Release)$') { | |
| throw "Unexpected prebuilt library artifact name: $($artifact.Name)" | |
| } | |
| $toolset = $Matches[1] | |
| $arch = $Matches[2] | |
| $config = $Matches[3] | |
| $destination = Join-Path 'artifacts/nuget-staging/lib/native' "$toolset/$arch/$config" | |
| New-Item -ItemType Directory -Force -Path $destination | Out-Null | |
| Copy-Item -Path (Join-Path $artifact.FullName '*') -Destination $destination -Recurse -Force | |
| } | |
| - name: Pack | |
| shell: pwsh | |
| run: ./scripts/nuget/Pack-CrtSysNuGet.ps1 -Version '${{ steps.version.outputs.package_version }}' -Toolset v142,v143,v145 | |
| - name: Pack GitHub release assets | |
| shell: pwsh | |
| run: ./scripts/nuget/Pack-CrtSysReleaseAssets.ps1 -Version '${{ steps.version.outputs.package_version }}' -Toolset v142,v143,v145 | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: crtsys-nuget-${{ steps.version.outputs.package_version }} | |
| path: artifacts/nuget/*.nupkg | |
| if-no-files-found: error | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: crtsys-release-assets-${{ steps.version.outputs.package_version }} | |
| path: artifacts/release/* | |
| if-no-files-found: error | |
| test-package-driver: | |
| name: Test NuGet driver package ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: pack | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x64, ARM, ARM64] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| vs_major: 17 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| vs_major: 17 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| runner: windows-2025-vs2026 | |
| windows_sdk: 10.0.26100.0 | |
| vs_major: 18 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: NuGet/setup-nuget@v2 | |
| - name: Ensure WDK | |
| if: ${{ matrix.toolset == 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' | |
| - name: Ensure WDK for ARM32 | |
| if: ${{ matrix.arch == 'ARM' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM | |
| - name: Ensure WDK for ARM64 old toolsets | |
| if: ${{ matrix.arch == 'ARM64' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM64 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-nuget-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/nuget | |
| - name: Build package consumer test driver | |
| shell: pwsh | |
| run: > | |
| ./scripts/nuget/Test-CrtSysNuGetMsBuildPackage.ps1 | |
| -PackageDirectory artifacts/nuget | |
| -Version '${{ needs.pack.outputs.package_version }}' | |
| -Toolset '${{ matrix.toolset }}' | |
| -Architecture '${{ matrix.arch }}' | |
| -Configuration '${{ matrix.config }}' | |
| -WindowsSdkVersion '${{ matrix.windows_sdk }}' | |
| -VisualStudioMajorVersion '${{ matrix.vs_major }}' | |
| test-package-layout: | |
| name: Validate NuGet package layout ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: pack | |
| runs-on: windows-2022 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x86, ARM] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: NuGet/setup-nuget@v2 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-nuget-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/nuget | |
| - name: Validate package layout | |
| shell: pwsh | |
| run: > | |
| ./scripts/nuget/Test-CrtSysNuGetPackage.ps1 | |
| -PackageDirectory artifacts/nuget | |
| -Version '${{ needs.pack.outputs.package_version }}' | |
| -Consumer Driver | |
| -Toolset '${{ matrix.toolset }}' | |
| -Architecture '${{ matrix.arch }}' | |
| -Configuration '${{ matrix.config }}' | |
| -SkipDriverBuild | |
| test-package-app: | |
| name: Test NuGet app package ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: pack | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x86, x64, ARM, ARM64] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| vs_major: 17 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| vs_major: 17 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| runner: windows-2025-vs2026 | |
| windows_sdk: 10.0.26100.0 | |
| vs_major: 18 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: NuGet/setup-nuget@v2 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-nuget-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/nuget | |
| - name: Build package app consumer test | |
| shell: pwsh | |
| run: > | |
| ./scripts/nuget/Test-CrtSysNuGetPackage.ps1 | |
| -PackageDirectory artifacts/nuget | |
| -Version '${{ needs.pack.outputs.package_version }}' | |
| -Consumer App | |
| -Toolset '${{ matrix.toolset }}' | |
| -Architecture '${{ matrix.arch }}' | |
| -Configuration '${{ matrix.config }}' | |
| -WindowsSdkVersion '${{ matrix.windows_sdk }}' | |
| -VisualStudioMajorVersion '${{ matrix.vs_major }}' | |
| test-release-prebuilt-cmake: | |
| name: Test release prebuilt CMake asset ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: pack | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x86, x64, ARM, ARM64] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| runner: windows-2022 | |
| windows_sdk: 10.0.22621.0 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| runner: windows-2025-vs2026 | |
| windows_sdk: 10.0.26100.0 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Ensure WDK | |
| if: ${{ matrix.toolset == 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' | |
| - name: Ensure WDK for x86 | |
| if: ${{ matrix.arch == 'x86' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ env.CRTSYS_WINDOWS_SDK_VERSION }}' -RequiredPlatforms x86 | |
| - name: Ensure WDK for ARM32 | |
| if: ${{ matrix.arch == 'ARM' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM | |
| - name: Ensure WDK for ARM64 old toolsets | |
| if: ${{ matrix.arch == 'ARM64' && matrix.toolset != 'v145' }} | |
| shell: pwsh | |
| run: ./scripts/nuget/Ensure-CrtSysWdk.ps1 -WindowsSdkVersion '${{ matrix.windows_sdk }}' -RequiredPlatforms ARM64 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-release-assets-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/release | |
| - name: Build prebuilt release CMake consumer test | |
| shell: pwsh | |
| run: | | |
| $windowsSdkVersion = '${{ matrix.windows_sdk }}' | |
| $wdkVersion = '' | |
| if ('${{ matrix.arch }}' -eq 'x86') { | |
| $wdkVersion = '${{ env.CRTSYS_WINDOWS_SDK_VERSION }}' | |
| } | |
| $parameters = @{ | |
| ReleaseDirectory = 'artifacts/release' | |
| Version = '${{ needs.pack.outputs.package_version }}' | |
| Toolset = '${{ matrix.toolset }}' | |
| Architecture = '${{ matrix.arch }}' | |
| Configuration = '${{ matrix.config }}' | |
| WindowsSdkVersion = $windowsSdkVersion | |
| } | |
| if (-not [string]::IsNullOrWhiteSpace($wdkVersion)) { | |
| $parameters.WdkVersion = $wdkVersion | |
| } | |
| ./scripts/nuget/Test-CrtSysReleaseAssets.ps1 @parameters | |
| test-release-prebuilt-layout: | |
| name: Validate release prebuilt layout ${{ matrix.vs_label }} ${{ matrix.toolset }} ${{ matrix.arch }} ${{ matrix.config }} | |
| needs: pack | |
| runs-on: windows-2022 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| toolset: [v142, v143, v145] | |
| arch: [x86, ARM] | |
| config: [Debug, Release] | |
| include: | |
| - toolset: v142 | |
| vs_label: VS2019 | |
| - toolset: v143 | |
| vs_label: VS2022 | |
| - toolset: v145 | |
| vs_label: VS2026 | |
| exclude: | |
| - toolset: v145 | |
| arch: ARM | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-release-assets-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/release | |
| - name: Validate prebuilt release layout | |
| shell: pwsh | |
| run: > | |
| ./scripts/nuget/Test-CrtSysReleaseAssets.ps1 | |
| -ReleaseDirectory artifacts/release | |
| -Version '${{ needs.pack.outputs.package_version }}' | |
| -Toolset '${{ matrix.toolset }}' | |
| -Architecture '${{ matrix.arch }}' | |
| -Configuration '${{ matrix.config }}' | |
| -SkipDriverBuild | |
| publish: | |
| name: Publish NuGet | |
| needs: [pack, test-package-driver, test-package-layout, test-package-app] | |
| if: ${{ (github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && inputs.publish) }} | |
| runs-on: windows-2022 | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: '10.0.x' | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-nuget-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/nuget | |
| - name: Validate NuGet trusted publishing user | |
| shell: pwsh | |
| run: | | |
| if ([string]::IsNullOrWhiteSpace('${{ vars.NUGET_TRUSTED_PUBLISHING_USER }}')) { | |
| throw 'Repository variable NUGET_TRUSTED_PUBLISHING_USER is required for NuGet Trusted Publishing.' | |
| } | |
| - name: NuGet login | |
| uses: NuGet/login@v1 | |
| id: nuget-login | |
| with: | |
| user: ${{ vars.NUGET_TRUSTED_PUBLISHING_USER }} | |
| - name: Publish to nuget.org | |
| shell: pwsh | |
| env: | |
| NUGET_API_KEY: ${{ steps.nuget-login.outputs.NUGET_API_KEY }} | |
| run: ./scripts/nuget/Push-CrtSysNuGet.ps1 -SkipDuplicate | |
| github-release: | |
| name: Upload GitHub Release Assets | |
| needs: [pack, test-package-driver, test-package-layout, test-package-app, test-release-prebuilt-cmake, test-release-prebuilt-layout] | |
| if: ${{ (github.event_name != 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/v')) || (github.event_name == 'workflow_dispatch' && inputs.github_release) }} | |
| runs-on: windows-2022 | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: actions/download-artifact@v7 | |
| with: | |
| name: crtsys-release-assets-${{ needs.pack.outputs.package_version }} | |
| path: artifacts/release | |
| - name: Create or update GitHub release | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| Set-Location '${{ github.workspace }}' | |
| $version = '${{ needs.pack.outputs.package_version }}' | |
| $tagName = "v$version" | |
| if ('${{ github.ref_type }}' -eq 'tag') { | |
| $tagName = '${{ github.ref_name }}' | |
| } | |
| $repo = '${{ github.repository }}' | |
| $assets = @(Get-ChildItem -Path artifacts\release -File | Sort-Object FullName | ForEach-Object { $_.FullName }) | |
| if ($assets.Count -eq 0) { | |
| throw 'No GitHub Release assets were found.' | |
| } | |
| & gh release view $tagName --repo $repo *> $null | |
| if ($LASTEXITCODE -eq 0) { | |
| Write-Host "Uploading assets to existing GitHub Release $tagName" | |
| & gh release upload $tagName @assets --repo $repo --clobber | |
| } else { | |
| Write-Host "Creating GitHub Release $tagName" | |
| $notes = @( | |
| "crtsys $version release assets." | |
| "" | |
| "- crtsys.$version.nupkg: offline NuGet package" | |
| "- crtsys-$version-prebuilt.zip: headers, docs, CMake helpers/package config, native MSBuild imports, and toolset-specific prebuilt libraries (v142/v143 for x86/x64/ARM/ARM64 and v145 for x86/x64/ARM64)" | |
| "- crtsys-$version-SHA256SUMS.txt: SHA-256 checksums" | |
| ) -join [Environment]::NewLine | |
| & gh release create $tagName @assets --repo $repo --target '${{ github.sha }}' --title "crtsys $version" --notes $notes | |
| } | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "GitHub Release upload failed with exit code $LASTEXITCODE." | |
| } |