From 137c772556cdd6f50c5a7934132cc200f92e5b77 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Mon, 12 Oct 2026 16:28:12 +0200 Subject: [PATCH] Push to the dioxus, tauri and winit examples on Windows in CI --- .github/workflows/windows-push.yml | 46 ++++++++ assets/brand/icon-macos.ico | Bin 0 -> 22458 bytes assets/brand/render.sh | 7 ++ ci/windows/example.ps1 | 177 +++++++++++++++++++++++++++++ examples/tauri/tauri.conf.json | 3 +- 5 files changed, 232 insertions(+), 1 deletion(-) create mode 100644 assets/brand/icon-macos.ico create mode 100644 ci/windows/example.ps1 diff --git a/.github/workflows/windows-push.yml b/.github/workflows/windows-push.yml index 6e3946d..2097218 100644 --- a/.github/workflows/windows-push.yml +++ b/.github/workflows/windows-push.yml @@ -43,3 +43,49 @@ jobs: WNS_OBJECT_ID: ${{ secrets.WNS_OBJECT_ID }} WNS_CLIENT_SECRET: ${{ secrets.WNS_CLIENT_SECRET }} run: ./ci/windows/w0.ps1 + example: + name: Example (${{ matrix.example }}) + if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository + runs-on: windows-latest + timeout-minutes: 90 + strategy: + matrix: + example: [dioxus, tauri, winit] + steps: + - uses: actions/checkout@v7 + - run: rustup toolchain install stable --profile minimal + - name: Install the Windows App SDK 2.5 runtime + shell: pwsh + run: | + $installer = Join-Path $env:RUNNER_TEMP 'WindowsAppRuntimeInstall-x64.exe' + Invoke-WebRequest -TimeoutSec 600 -OutFile $installer 'https://aka.ms/windowsappsdk/2.5/latest/windowsappruntimeinstall-x64.exe' + $install = Start-Process $installer -ArgumentList '--quiet' -NoNewWindow -PassThru + # The handle is taken now so the exit code stays readable. + $null = $install.Handle + if (-not $install.WaitForExit(600000)) { $install.Kill(); throw 'the runtime installer did not finish within 10 minutes' } + if ($install.ExitCode -ne 0) { throw "the runtime installer exited with $($install.ExitCode)" } + - name: Build the ${{ matrix.example }} example + shell: pwsh + env: + EXAMPLE: ${{ matrix.example }} + PUSHUPS_WNS_REMOTE_ID: ${{ secrets.WNS_OBJECT_ID }} + run: | + # The Dioxus example's `firebase_config!` reads this file on every target. + Copy-Item tests/fixtures/google-services.json "examples/$env:EXAMPLE/google-services.json" + $map = @{ + dioxus = @{ Manifest = 'examples/dioxus/Cargo.toml'; Args = @('--no-default-features', '--features', 'desktop') } + tauri = @{ Manifest = 'examples/tauri/Cargo.toml'; Args = @() } + winit = @{ Manifest = 'examples/winit/Cargo.toml'; Args = @() } + } + $entry = $map[$env:EXAMPLE] + $buildArgs = $entry.Args + cargo +stable build --release --manifest-path $entry.Manifest @buildArgs + - name: Run the ${{ matrix.example }} example with WNS pushes + shell: pwsh + env: + WNS_TENANT_ID: ${{ secrets.WNS_TENANT_ID }} + WNS_APP_ID: ${{ secrets.WNS_APP_ID }} + WNS_OBJECT_ID: ${{ secrets.WNS_OBJECT_ID }} + WNS_CLIENT_SECRET: ${{ secrets.WNS_CLIENT_SECRET }} + run: | + ./ci/windows/example.ps1 "$env:GITHUB_WORKSPACE\examples\${{ matrix.example }}\target\release\pushups-${{ matrix.example }}-example.exe" diff --git a/assets/brand/icon-macos.ico b/assets/brand/icon-macos.ico new file mode 100644 index 0000000000000000000000000000000000000000..a46b8bfa96f2d67204f44f0be0603b239d5ec8af GIT binary patch literal 22458 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 V;13kJSinj`n!EO>=BQYn`G3?Z(P#hw literal 0 HcmV?d00001 diff --git a/assets/brand/render.sh b/assets/brand/render.sh index e6bfc8b..54ea6a0 100755 --- a/assets/brand/render.sh +++ b/assets/brand/render.sh @@ -9,6 +9,13 @@ mkdir -p "$brand/png" for size in 32 128 256 512 1024; do rsvg-convert --width "$size" --height "$size" "$brand/icon-macos.svg" --output "$brand/png/icon-macos-$size.png" done +# The Windows resource icon `tauri-build` compiles into the Tauri example, which it reads only from an `.ico`. +ico=$(mktemp -d) +for size in 16 32 48 256; do + rsvg-convert --width "$size" --height "$size" "$brand/icon-macos.svg" --output "$ico/$size.png" +done +convert "$ico/16.png" "$ico/32.png" "$ico/48.png" "$ico/256.png" "$brand/icon-macos.ico" +rm -r "$ico" # The repository's social preview, uploaded in the GitHub settings. rsvg-convert --width 1280 --height 640 "$brand/social.svg" --output "$brand/png/social.png" diff --git a/ci/windows/example.ps1 b/ci/windows/example.ps1 new file mode 100644 index 0000000..18cf5e4 --- /dev/null +++ b/ci/windows/example.ps1 @@ -0,0 +1,177 @@ +# Runs one pushups example exe (Dioxus, Tauri or winit) with real WNS pushes, for the X1 proofs. +# The exe must have been built with PUSHUPS_WNS_REMOTE_ID set, so a process Windows starts for a +# push knows the remote id without any file to read. +# Run from the repository root after building the example, with WNS_TENANT_ID, WNS_APP_ID, +# WNS_OBJECT_ID and WNS_CLIENT_SECRET set. Takes the built exe's path. +param([Parameter(Mandatory)][string] $Exe) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version Latest + +# The Foundation package metapackage 2.5.1 depends on, the release ci/windows/bindings.sh pins. +$Foundation = '2.3.12' +# WNS may take minutes to answer a channel request. +$ChannelBound = [TimeSpan]::FromSeconds(240) +$PushBound = [TimeSpan]::FromSeconds(90) +# A push-started process also starts a window and a web view environment. +$ActivationBound = [TimeSpan]::FromSeconds(180) +$ExitBound = [TimeSpan]::FromSeconds(20) + +foreach ($name in 'WNS_TENANT_ID', 'WNS_APP_ID', 'WNS_OBJECT_ID', 'WNS_CLIENT_SECRET') { + if (-not [Environment]::GetEnvironmentVariable($name)) { throw "$name is not set" } +} + +$exe = (Resolve-Path $Exe).Path +$app = [IO.Path]::GetFileNameWithoutExtension($exe) +$dir = Split-Path $exe +$log = Join-Path $env:TEMP 'pushups-example.log' +$work = Join-Path ($env:RUNNER_TEMP ?? [IO.Path]::GetTempPath()) "example-$app" +$verdict = [Collections.Generic.List[string]]::new() +$passed = $true + +function Note([string] $line) { + Write-Host $line + $verdict.Add($line) +} + +# Runs `$done` until it returns something or `$bound` passes on a monotonic clock. +function Wait-Until([TimeSpan] $bound, [scriptblock] $done) { + $clock = [Diagnostics.Stopwatch]::StartNew() + while ($clock.Elapsed -lt $bound) { + $result = & $done + if ($result) { return $result } + Start-Sleep -Milliseconds 250 + } + return $null +} + +function First-Line([string] $file, [string] $pattern) { + Get-Content $file -ErrorAction SilentlyContinue | Where-Object { $_ -match $pattern } | Select-Object -First 1 +} + +function Send-Push([string] $uri, [string] $token, [string] $payload) { + $response = Invoke-WebRequest -Method Post -Uri $uri -TimeoutSec 60 -SkipHttpErrorCheck ` + -Headers @{ Authorization = "Bearer $token"; 'X-WNS-Type' = 'wns/raw' } ` + -ContentType 'application/octet-stream' -Body ([Text.Encoding]::UTF8.GetBytes($payload)) + $wns = foreach ($header in 'X-WNS-Status', 'X-WNS-NotificationStatus', 'X-WNS-Error-Description') { + if ($response.Headers.ContainsKey($header)) { "$header=$($response.Headers[$header] -join ',')" } + } + "HTTP $($response.StatusCode) $($wns -join ' ')" +} + +# Ends the app's process and reports whether it left within the bound. +function Stop-App([string] $label, [System.Diagnostics.Process] $p) { + $p.Kill() | Out-Null + $exited = $p.WaitForExit([int] $ExitBound.TotalMilliseconds) + if (-not $exited) { Note "- the $label app did not exit within $ExitBound" } + $exited +} + +Note "## X1 on $((Get-CimInstance Win32_OperatingSystem).Caption) $([Environment]::OSVersion.Version), $app" + +# The bootstrapper the 2.5 channel install loads, which a desktop machine ships nowhere, fetched as w0.ps1 does. +$bootstrap = Join-Path $dir 'Microsoft.WindowsAppRuntime.Bootstrap.dll' +if (Test-Path $bootstrap) { + Note '- the bootstrapper already beside the exe' +} else { + New-Item -ItemType Directory -Force $work | Out-Null + $package = Join-Path $work 'foundation.zip' + Invoke-WebRequest -TimeoutSec 600 -OutFile $package ` + "https://api.nuget.org/v3-flatcontainer/microsoft.windowsappsdk.foundation/$Foundation/microsoft.windowsappsdk.foundation.$Foundation.nupkg" + Expand-Archive -Force $package (Join-Path $work 'foundation') + Copy-Item (Join-Path $work 'foundation/runtimes/win-x64/native/Microsoft.WindowsAppRuntime.Bootstrap.dll') $bootstrap + Note '- the bootstrapper copied beside the exe' +} + +# The temp log a process started with nothing reading its output writes to. +Remove-Item $log -ErrorAction SilentlyContinue + +$process = Start-Process -FilePath $exe -WorkingDirectory $dir -NoNewWindow -PassThru + +$uri = $null +$tokenLine = Wait-Until $ChannelBound { First-Line $log 'ui token at_ms=\d+ Wns \{ channel_uri: "([^"]+)"' } +if (-not $tokenLine) { + Note "- no token within $ChannelBound" + $passed = $false +} elseif ($tokenLine -match 'channel_uri: "([^"]+)"') { + $uri = $matches[1] + Write-Host "::add-mask::$uri" + Note "- channel created on $(([Uri] $uri).Host), $($tokenLine -replace '^.*ui token at_ms=\d+ ', '')" +} else { + Note "- the token line has no channel uri: $tokenLine" + $passed = $false +} + +$token = $null +if ($uri) { + try { + $token = (Invoke-RestMethod -Method Post -TimeoutSec 60 ` + -Uri "https://login.microsoftonline.com/$env:WNS_TENANT_ID/oauth2/v2.0/token" ` + -Body @{ + grant_type = 'client_credentials' + client_id = $env:WNS_APP_ID + client_secret = $env:WNS_CLIENT_SECRET + scope = 'https://wns.windows.com/.default' + }).access_token + Write-Host "::add-mask::$token" + Note '- access token issued for https://wns.windows.com/.default' + } catch { + $reason = if ($_.ErrorDetails) { $_.ErrorDetails.Message } else { $_.Exception.Message } + Note "- access token refused: $reason" + $token = $null + $passed = $false + } +} + +if ($uri -and $token) { + $sent = [DateTimeOffset]::Now.ToUnixTimeMilliseconds() + $payload = '{"seq":"1","sent_at_ms":"' + $sent + '"}' + try { + $result = Send-Push $uri $token $payload + } catch { + $result = "failed: $($_.Exception.Message)" + } + Note "- push 1 to the running app: $result" + $got = Wait-Until $PushBound { + $ui = First-Line $log 'ui message at_ms=\d+ started_app=false seq=1 ' + $handler = First-Line $log 'handler started_app=false .*seq=1 ' + if ($ui -and $handler) { [pscustomobject]@{ Ui = $ui; Handler = $handler } } + } + if ($got) { + Note "- running: $($got.Ui)" + Note "- running: $($got.Handler)" + } else { + Note "- the running app did not get seq=1 within $PushBound" + $passed = $false + } + if (-not (Stop-App 'running' $process)) { $passed = $false } + + # The same channel still reaches the app once the process is gone. + $sent = [DateTimeOffset]::Now.ToUnixTimeMilliseconds() + $payload = '{"seq":"2","sent_at_ms":"' + $sent + '"}' + try { + $result = Send-Push $uri $token $payload + } catch { + $result = "failed: $($_.Exception.Message)" + } + Note "- push 2 with the app stopped: $result" + $got2 = Wait-Until $ActivationBound { First-Line $log 'handler started_app=true .*seq=2 ' } + if ($got2) { + Note "- push-started: $got2" + $started = Wait-Until $ExitBound { Get-Process -Name $app -ErrorAction SilentlyContinue | Select-Object -First 1 } + if ($started) { + if (-not (Stop-App 'push-started' $started)) { $passed = $false } + } else { + Note '- the push-started process was already gone when it was looked for' + } + } else { + Note "- the stopped app was not started with seq=2 within $ActivationBound" + $passed = $false + } +} + +Write-Host "--- $app pushups-example.log" +Get-Content $log -ErrorAction SilentlyContinue | Write-Host + +if ($env:GITHUB_STEP_SUMMARY) { $verdict | Add-Content $env:GITHUB_STEP_SUMMARY } +exit ([int] (-not $passed)) diff --git a/examples/tauri/tauri.conf.json b/examples/tauri/tauri.conf.json index bad4533..73f16be 100644 --- a/examples/tauri/tauri.conf.json +++ b/examples/tauri/tauri.conf.json @@ -18,7 +18,8 @@ "icon": [ "../../assets/brand/png/icon-macos-512.png", "../../assets/brand/png/icon-macos-128.png", - "../../assets/brand/png/icon-macos-32.png" + "../../assets/brand/png/icon-macos-32.png", + "../../assets/brand/icon-macos.ico" ] } }