Build and Release #16
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: Build and Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| env: | |
| PROJECT_PATH: CollimationCircles/CollimationCircles.csproj | |
| FRAMEWORK: net10.0 | |
| APP_NAME: CollimationCircles | |
| DOTNET_VERSION: '10.0.x' | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runtime: win-x64 | |
| os: windows-latest | |
| index: 1 | |
| ready2run: true | |
| - runtime: win-arm64 | |
| os: windows-latest | |
| index: 2 | |
| ready2run: false | |
| - runtime: linux-x64 | |
| os: ubuntu-latest | |
| index: 3 | |
| ready2run: true | |
| - runtime: linux-arm64 | |
| os: ubuntu-latest | |
| index: 4 | |
| ready2run: false | |
| - runtime: osx-x64 | |
| os: macos-latest | |
| index: 5 | |
| ready2run: true | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v5 | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v5 | |
| with: | |
| dotnet-version: ${{ env.DOTNET_VERSION }} | |
| - name: Extract version from csproj | |
| id: version | |
| shell: pwsh | |
| run: | | |
| [xml]$xml = Get-Content "${{ env.PROJECT_PATH }}" | |
| $version = ($xml.Project.PropertyGroup.InformationalVersion | Where-Object { $_ }) | Select-Object -First 1 | |
| $version = $version.Trim() | |
| Write-Host "Version: $version" | |
| echo "APP_VERSION=$version" >> $env:GITHUB_OUTPUT | |
| - name: Restore dependencies | |
| run: dotnet restore ${{ env.PROJECT_PATH }} -r ${{ matrix.runtime }} /p:PublishReadyToRun=${{ matrix.ready2run }} | |
| - name: Publish | |
| shell: pwsh | |
| run: | | |
| $publishArgs = @( | |
| "publish" | |
| "${{ env.PROJECT_PATH }}" | |
| "-c", "Release" | |
| "-r", "${{ matrix.runtime }}" | |
| "-o", "./publish/${{ matrix.runtime }}" | |
| "--self-contained", "true" | |
| "--no-restore" | |
| "/p:PublishSingleFile=true" | |
| "/p:PublishReadyToRun=${{ matrix.ready2run }}" | |
| "/p:DebugType=None" | |
| "/p:DebugSymbols=false" | |
| ) | |
| if ("${{ matrix.runtime }}" -eq "osx-x64") { | |
| $publishArgs += "/p:UseAppHost=true" | |
| } | |
| $command = "dotnet " + ($publishArgs -join " ") | |
| Write-Host $command -ForegroundColor Green | |
| Invoke-Expression $command | |
| if ($LASTEXITCODE -ne 0) { | |
| throw "dotnet publish failed with exit code $LASTEXITCODE" | |
| } | |
| # ?? Linux: Package as tar.gz (preserves executable permissions) ???????? | |
| - name: Package (Linux) | |
| if: startsWith(matrix.runtime, 'linux-') | |
| shell: bash | |
| env: | |
| APP_VERSION: ${{ steps.version.outputs.APP_VERSION }} | |
| RUNTIME: ${{ matrix.runtime }} | |
| run: | | |
| set -euo pipefail | |
| output="./publish" | |
| # Remove icon.icns since it's only for macOS | |
| rm -f "${output}/${RUNTIME}/icon.icns" | |
| # Make the main binary executable | |
| chmod +x "${output}/${RUNTIME}/${APP_NAME}" | |
| tarName="${output}/${{ matrix.index }}-${APP_NAME}-${APP_VERSION}-${RUNTIME}.tar.gz" | |
| tar -czf "${tarName}" -C "${output}/${RUNTIME}" . | |
| echo "Created: ${tarName}" | |
| # ?? macOS: Create .app bundle ??????????????????????????????????????? | |
| - name: Create macOS .app bundle | |
| if: matrix.runtime == 'osx-x64' | |
| shell: pwsh | |
| run: | | |
| $appName = "${{ env.APP_NAME }}" | |
| $appVersion = "${{ steps.version.outputs.APP_VERSION }}" | |
| $bundle = "$appName.app" | |
| $output = "./publish" | |
| $runtime = "${{ matrix.runtime }}" | |
| # Create bundle directory structure | |
| New-Item -Path "$output/$bundle/Contents/MacOS" -ItemType Directory -Force | |
| New-Item -Path "$output/$bundle/Contents/Resources" -ItemType Directory -Force | |
| # Create Info.plist | |
| $plistContent = @" | |
| <?xml version="1.0" encoding="utf-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <dict> | |
| <key>CFBundleIconFile</key> | |
| <string>icon.icns</string> | |
| <key>CFBundleIdentifier</key> | |
| <string>com.saimons.$appName</string> | |
| <key>CFBundleName</key> | |
| <string>$appName</string> | |
| <key>CFBundleVersion</key> | |
| <string>$appVersion</string> | |
| <key>LSMinimumSystemVersion</key> | |
| <string>11</string> | |
| <key>CFBundleExecutable</key> | |
| <string>$appName</string> | |
| <key>CFBundleInfoDictionaryVersion</key> | |
| <string>6.0</string> | |
| <key>CFBundlePackageType</key> | |
| <string>APPL</string> | |
| <key>CFBundleShortVersionString</key> | |
| <string>$appVersion</string> | |
| <key>NSHighResolutionCapable</key> | |
| <true/> | |
| </dict> | |
| </plist> | |
| "@ | |
| $plistContent | Set-Content -Path "$output/$bundle/Contents/Info.plist" -Encoding UTF8 | |
| # Copy application files to Contents/MacOS | |
| Copy-Item -Path "$output/$runtime/*" -Destination "$output/$bundle/Contents/MacOS" -Recurse | |
| # Move icon to Contents/Resources | |
| if (Test-Path "$output/$bundle/Contents/MacOS/icon.icns") { | |
| Move-Item -Path "$output/$bundle/Contents/MacOS/icon.icns" -Destination "$output/$bundle/Contents/Resources/" | |
| } | |
| # Make executable | |
| chmod +x "$output/$bundle/Contents/MacOS/$appName" | |
| # ?? Windows / macOS: Package as ZIP ????????????????????????????????? | |
| - name: Package (Windows) | |
| if: startsWith(matrix.runtime, 'win-') | |
| shell: pwsh | |
| run: | | |
| $appVersion = "${{ steps.version.outputs.APP_VERSION }}" | |
| $runtime = "${{ matrix.runtime }}" | |
| $output = "./publish" | |
| # Remove icon.icns since it's only for macOS | |
| $icnsPath = "$output/$runtime/icon.icns" | |
| if (Test-Path $icnsPath) { | |
| Remove-Item -Path $icnsPath | |
| } | |
| $zipName = "$output/${{ matrix.index }}-${{ env.APP_NAME }}-$appVersion-$runtime.zip" | |
| Compress-Archive -Force "$output/$runtime/*" $zipName | |
| Write-Host "Created: $zipName" -ForegroundColor Green | |
| - name: Package (macOS) | |
| if: matrix.runtime == 'osx-x64' | |
| shell: pwsh | |
| run: | | |
| $appVersion = "${{ steps.version.outputs.APP_VERSION }}" | |
| $runtime = "${{ matrix.runtime }}" | |
| $output = "./publish" | |
| $bundle = "${{ env.APP_NAME }}.app" | |
| $zipName = "$output/${{ matrix.index }}-${{ env.APP_NAME }}-$appVersion-$runtime.zip" | |
| Compress-Archive -Force "$output/$bundle" $zipName | |
| Write-Host "Created: $zipName" -ForegroundColor Green | |
| # ?? Upload artifacts ???????????????????????????????????????????????? | |
| - name: Upload build artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: ${{ env.APP_NAME }}-${{ matrix.runtime }} | |
| path: | | |
| ./publish/${{ matrix.index }}-*.zip | |
| ./publish/${{ matrix.index }}-*.tar.gz | |
| retention-days: 30 | |
| release: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v5 | |
| with: | |
| path: ./artifacts | |
| merge-multiple: true | |
| - name: List artifacts | |
| run: find ./artifacts -type f \( -name "*.zip" -o -name "*.tar.gz" \) | sort | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| generate_release_notes: true | |
| draft: false | |
| prerelease: false | |
| files: | | |
| ./artifacts/*.zip | |
| ./artifacts/*.tar.gz | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |