Skip to content

Build and Release

Build and Release #16

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 }}