diff --git a/.github/workflows/nuget-static-graphics.yml b/.github/workflows/nuget-static-graphics.yml
index 186ba1d..6a0cb48 100644
--- a/.github/workflows/nuget-static-graphics.yml
+++ b/.github/workflows/nuget-static-graphics.yml
@@ -8,6 +8,11 @@ on:
required: true
default: false
type: boolean
+ publish_to_release:
+ description: Publish NuGet package and smoke apps to GitHub Release
+ required: true
+ default: true
+ type: boolean
push:
tags:
- "static-graphics-v*"
@@ -215,3 +220,135 @@ jobs:
--api-key "$NUGET_API_KEY" \
--skip-duplicate
done
+
+ smoke-avalonia:
+ needs: pack
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - rid: win-x64
+ runner: windows-2022
+ msvc_arch: x64
+ - rid: win-arm64
+ runner: windows-2022
+ msvc_arch: amd64_arm64
+ - rid: linux-x64
+ runner: ubuntu-latest
+ - rid: linux-arm64
+ runner: ubuntu-24.04-arm
+ - rid: osx-x64
+ runner: macos-13
+ - rid: osx-arm64
+ runner: macos-latest
+ runs-on: ${{ matrix.runner }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup MSVC environment
+ if: ${{ startsWith(matrix.rid, 'win-') }}
+ uses: ilammy/msvc-dev-cmd@v1
+ with:
+ arch: ${{ matrix.msvc_arch }}
+
+ - name: Install Linux publish dependencies
+ if: ${{ startsWith(matrix.rid, 'linux-') }}
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y clang lld zlib1g-dev libfontconfig1-dev
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: "10.0.x"
+
+ - name: Download NuGet package
+ uses: actions/download-artifact@v4
+ with:
+ name: nuget-static-graphics
+ path: artifacts/nuget
+
+ - name: Publish Avalonia single-file smoke app
+ shell: pwsh
+ run: |
+ $ErrorActionPreference = "Stop"
+ $package = Get-ChildItem -Path "artifacts/nuget" -Filter "Shiroka.Avalonia.StaticLink.*.nupkg" | Select-Object -First 1
+ if (-not $package) { throw "StaticLink NuGet package was not downloaded." }
+ if ($package.BaseName -notmatch '^Shiroka\.Avalonia\.StaticLink\.(.+)$') { throw "Unexpected package name: $($package.Name)" }
+ $version = $Matches[1]
+ $projectDir = Join-Path $PWD "artifacts/avalonia-smoke-src"
+ pwsh ./scripts/create-avalonia-smoke.ps1 -ProjectDir $projectDir -NuGetSource (Resolve-Path "artifacts/nuget") -StaticLinkVersion $version
+ dotnet publish (Join-Path $projectDir "AvaloniaStaticLinkSmoke.csproj") `
+ -c Release `
+ -r "${{ matrix.rid }}" `
+ --configfile (Join-Path $projectDir "NuGet.config") `
+ /p:PublishAot=true `
+ /p:SelfContained=true `
+ /p:PublishSingleFile=true `
+ /p:StripSymbols=true `
+ /p:PublishDir="$PWD/artifacts/smoke-${{ matrix.rid }}/"
+
+ - name: Verify no dynamic graphics libraries remain
+ shell: pwsh
+ run: |
+ $publishDir = "artifacts/smoke-${{ matrix.rid }}"
+ $blocked = Get-ChildItem -Path $publishDir -Recurse -File | Where-Object {
+ $_.Name -in @("libSkiaSharp.dll", "libHarfBuzzSharp.dll", "av_libglesv2.dll", "libSkiaSharp.so", "libHarfBuzzSharp.so", "libSkiaSharp.dylib", "libHarfBuzzSharp.dylib")
+ }
+ if ($blocked) {
+ $blocked | ForEach-Object { Write-Error "Unexpected dynamic graphics library: $($_.FullName)" }
+ exit 1
+ }
+ Get-ChildItem -Path $publishDir -Recurse -File | ForEach-Object { $_.FullName }
+
+ - name: Upload Avalonia smoke app
+ uses: actions/upload-artifact@v4
+ with:
+ name: avalonia-smoke-${{ matrix.rid }}
+ path: artifacts/smoke-${{ matrix.rid }}/**
+ if-no-files-found: error
+
+ release:
+ runs-on: ubuntu-latest
+ needs:
+ - pack
+ - smoke-avalonia
+ if: ${{ startsWith(github.ref, 'refs/tags/static-graphics-v') || (github.event_name == 'workflow_dispatch' && inputs.publish_to_release == true) }}
+ permissions:
+ contents: write
+ steps:
+ - name: Download release artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: release-artifacts
+
+ - name: Prepare release files
+ run: |
+ mkdir -p release-files
+ find release-artifacts/nuget-static-graphics -type f \( -name '*.nupkg' -o -name '*.snupkg' \) -exec cp {} release-files/ \;
+ for dir in release-artifacts/avalonia-smoke-*; do
+ [ -d "$dir" ] || continue
+ name="$(basename "$dir")"
+ (cd "$dir" && zip -r "../../release-files/$name.zip" .)
+ done
+ ls -la release-files
+
+ - name: Publish GitHub Release
+ env:
+ GH_TOKEN: ${{ github.token }}
+ run: |
+ if [ "${GITHUB_REF_TYPE}" = "tag" ]; then
+ release_tag="${GITHUB_REF_NAME}"
+ title="${GITHUB_REF_NAME}"
+ else
+ release_tag="static-graphics-smoke-${GITHUB_RUN_NUMBER}"
+ title="Static graphics smoke ${GITHUB_RUN_NUMBER}"
+ fi
+
+ if gh release view "$release_tag" >/dev/null 2>&1; then
+ gh release upload "$release_tag" release-files/* --clobber
+ else
+ gh release create "$release_tag" release-files/* \
+ --title "$title" \
+ --notes "NuGet package plus Avalonia 11.3.14 NativeAOT single-file smoke apps for win-x64, win-arm64, linux-x64, linux-arm64, osx-x64, and osx-arm64."
+ fi
diff --git a/scripts/create-avalonia-smoke.ps1 b/scripts/create-avalonia-smoke.ps1
new file mode 100644
index 0000000..4545914
--- /dev/null
+++ b/scripts/create-avalonia-smoke.ps1
@@ -0,0 +1,133 @@
+param(
+ [Parameter(Mandatory = $true)]
+ [string]$ProjectDir,
+
+ [Parameter(Mandatory = $true)]
+ [string]$NuGetSource,
+
+ [Parameter(Mandatory = $true)]
+ [string]$StaticLinkVersion
+)
+
+$ErrorActionPreference = "Stop"
+
+New-Item -ItemType Directory -Path $ProjectDir -Force | Out-Null
+
+@"
+
+
+
+
+
+
+
+
+"@ | Set-Content -Path (Join-Path $ProjectDir "NuGet.config") -Encoding UTF8
+
+@"
+
+
+ WinExe
+ net10.0
+ enable
+ enable
+ true
+ true
+ true
+ true
+ true
+ false
+ true
+
+
+
+
+
+
+
+
+
+"@ | Set-Content -Path (Join-Path $ProjectDir "AvaloniaStaticLinkSmoke.csproj") -Encoding UTF8
+
+@"
+using Avalonia;
+
+namespace AvaloniaStaticLinkSmoke;
+
+internal static class Program
+{
+ [STAThread]
+ public static void Main(string[] args) => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
+
+ public static AppBuilder BuildAvaloniaApp()
+ => AppBuilder.Configure()
+ .UsePlatformDetect()
+ .LogToTrace();
+}
+"@ | Set-Content -Path (Join-Path $ProjectDir "Program.cs") -Encoding UTF8
+
+@"
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+namespace AvaloniaStaticLinkSmoke;
+
+public sealed partial class App : Application
+{
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ desktop.MainWindow = new MainWindow();
+ }
+
+ base.OnFrameworkInitializationCompleted();
+ }
+}
+"@ | Set-Content -Path (Join-Path $ProjectDir "App.axaml.cs") -Encoding UTF8
+
+@"
+
+
+
+
+
+"@ | Set-Content -Path (Join-Path $ProjectDir "App.axaml") -Encoding UTF8
+
+@"
+using Avalonia.Controls;
+
+namespace AvaloniaStaticLinkSmoke;
+
+public sealed partial class MainWindow : Window
+{
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+}
+"@ | Set-Content -Path (Join-Path $ProjectDir "MainWindow.axaml.cs") -Encoding UTF8
+
+@"
+
+
+
+
+
+
+
+
+"@ | Set-Content -Path (Join-Path $ProjectDir "MainWindow.axaml") -Encoding UTF8