|
15 | 15 | - 'vm/**' |
16 | 16 | - 'Ports/WindowsPort/**' |
17 | 17 | - 'maven/windows/**' |
| 18 | + - 'scripts/gen-windows-uwp-stubs.py' |
| 19 | + - 'maven/build-engine/src/main/java/com/codename1/builders/WindowsNativeBuilder.java' |
| 20 | + - 'maven/build-engine/src/test/java/com/codename1/builders/WindowsNativeBuilderArchTest.java' |
| 21 | + - 'maven/build-engine/src/test/resources/com/codename1/builders/xbox-smoke-AppxManifest.xml' |
18 | 22 | - '!vm/**/README.md' |
19 | 23 | - '!vm/**/readme.md' |
20 | 24 | - '!vm/**/docs/**' |
|
25 | 29 | - 'vm/**' |
26 | 30 | - 'Ports/WindowsPort/**' |
27 | 31 | - 'maven/windows/**' |
| 32 | + - 'scripts/gen-windows-uwp-stubs.py' |
| 33 | + - 'maven/build-engine/src/main/java/com/codename1/builders/WindowsNativeBuilder.java' |
| 34 | + - 'maven/build-engine/src/test/java/com/codename1/builders/WindowsNativeBuilderArchTest.java' |
| 35 | + - 'maven/build-engine/src/test/resources/com/codename1/builders/xbox-smoke-AppxManifest.xml' |
28 | 36 |
|
29 | 37 | concurrency: |
30 | 38 | # Only the latest revision needs validation. PR numbers keep forks isolated; |
@@ -155,13 +163,156 @@ jobs: |
155 | 163 | test -f core/target/classes/com/codename1/ui/Form.class |
156 | 164 | test -f windows/target/classes/com/codename1/impl/windows/WindowsImplementation.class |
157 | 165 |
|
| 166 | + # A UWP (Xbox Developer Mode) build compiles the desktop-only natives |
| 167 | + # out and links generated stubs in their place; a native added to one of |
| 168 | + # those files without regenerating would fail only the UWP link below. |
| 169 | + - name: UWP stubs are current |
| 170 | + run: python3 scripts/gen-windows-uwp-stubs.py --check |
| 171 | + |
| 172 | + # Builds the desktop exe and the UWP one (app partition, WindowsApp.lib |
| 173 | + # only, /APPCONTAINER): the UWP link is the gate that every Win32 call the |
| 174 | + # port makes in that build exists inside the app container. |
158 | 175 | - name: Cross-compile the native Windows .exe (clang-cl + xwin) |
159 | 176 | env: |
160 | 177 | CN1_XWIN_SYSROOT: ${{ runner.temp }}/xwin-sdk |
161 | 178 | CN1_CLANG_CL: clang-cl |
162 | 179 | CN1_LLVM_RC: llvm-rc |
| 180 | + CN1_UWP_EXE_OUT: ${{ github.workspace }}/uwp-smoke/app.exe |
163 | 181 | run: | |
164 | 182 | cd vm |
165 | 183 | JAVA_HOME="$JDK_8_HOME" mvn -B -pl tests -am test \ |
166 | 184 | '-Dtest=CleanTargetIntegrationTest#crossCompilesWindowsExeWithXwin' \ |
167 | 185 | '-Dsurefire.failIfNoSpecifiedTests=false' |
| 186 | + test -f "$CN1_UWP_EXE_OUT" |
| 187 | +
|
| 188 | + # The development certificate windows.xbox builds create, made by the |
| 189 | + # builder's own openssl commands; the Windows job signs with it, so a |
| 190 | + # certificate Windows refuses fails there. |
| 191 | + - name: Create the Xbox development certificate (WindowsNativeBuilder) |
| 192 | + env: |
| 193 | + CN1_XBOX_DEVCERT_OUT: ${{ github.workspace }}/uwp-smoke/devcert |
| 194 | + RETRY_ONLY_MATCHING: transient |
| 195 | + RETRY_ATTEMPTS: '3' |
| 196 | + RETRY_DELAY_SECONDS: '60' |
| 197 | + run: | |
| 198 | + set -euo pipefail |
| 199 | + mkdir -p ~/.codenameone |
| 200 | + cp maven/UpdateCodenameOne.jar ~/.codenameone/ |
| 201 | + cd maven |
| 202 | + JAVA_HOME="$JDK_8_HOME" bash ../scripts/ci/retry.sh mvn -B -pl build-engine -am install \ |
| 203 | + -DskipTests -Dmaven.javadoc.skip=true -Plocal-dev-javase |
| 204 | + JAVA_HOME="$JDK_8_HOME" mvn -B -pl build-engine test -Plocal-dev-javase \ |
| 205 | + '-Dtest=WindowsNativeBuilderArchTest' -Dsurefire.failIfNoSpecifiedTests=false |
| 206 | + test -s "$CN1_XBOX_DEVCERT_OUT/dev.pfx" |
| 207 | + test -s "$CN1_XBOX_DEVCERT_OUT/dev.cer" |
| 208 | +
|
| 209 | + # The manifest is pinned to WindowsNativeBuilder.buildXboxAppxManifest by |
| 210 | + # WindowsNativeBuilderArchTest, so the run below installs what windows.xbox |
| 211 | + # builds ship. |
| 212 | + - name: Upload the UWP smoke app |
| 213 | + uses: actions/upload-artifact@v4 |
| 214 | + with: |
| 215 | + name: uwp-smoke |
| 216 | + path: | |
| 217 | + uwp-smoke/app.exe |
| 218 | + uwp-smoke/devcert/dev.pfx |
| 219 | + uwp-smoke/devcert/dev.cer |
| 220 | + maven/build-engine/src/test/resources/com/codename1/builders/xbox-smoke-AppxManifest.xml |
| 221 | + if-no-files-found: error |
| 222 | + retention-days: 3 |
| 223 | + |
| 224 | + # Phase 1's proof without a console: the cross-built UWP app is packed, signed, |
| 225 | + # installed and launched as a real UWP activation (app container, CoreWindow, |
| 226 | + # swap chain) on a Windows runner. The app writes a marker into its package |
| 227 | + # LocalState once its first form has painted; no marker fails the job. |
| 228 | + uwp-run: |
| 229 | + name: install + launch the UWP package (Windows x64) |
| 230 | + needs: cross-compile |
| 231 | + runs-on: windows-latest |
| 232 | + timeout-minutes: 20 |
| 233 | + steps: |
| 234 | + - name: Download the UWP smoke app |
| 235 | + uses: actions/download-artifact@v4 |
| 236 | + with: |
| 237 | + name: uwp-smoke |
| 238 | + path: uwp-smoke |
| 239 | + |
| 240 | + - name: Pack, sign and install |
| 241 | + shell: pwsh |
| 242 | + run: | |
| 243 | + $ErrorActionPreference = 'Stop' |
| 244 | + $root = Resolve-Path uwp-smoke |
| 245 | + $layout = Join-Path $env:RUNNER_TEMP 'uwp-layout' |
| 246 | + New-Item -ItemType Directory -Force (Join-Path $layout 'Assets') | Out-Null |
| 247 | + Copy-Item (Join-Path $root 'uwp-smoke/app.exe') (Join-Path $layout 'app.exe') |
| 248 | + $manifest = Get-ChildItem -Recurse $root -Filter 'xbox-smoke-AppxManifest.xml' | Select-Object -First 1 |
| 249 | + Copy-Item $manifest.FullName (Join-Path $layout 'AppxManifest.xml') |
| 250 | + Add-Type -AssemblyName System.Drawing |
| 251 | + foreach ($logo in 'StoreLogo','Square150x150Logo','Square44x44Logo','SplashScreen') { |
| 252 | + $bmp = New-Object System.Drawing.Bitmap 150,150 |
| 253 | + $g = [System.Drawing.Graphics]::FromImage($bmp); $g.Clear([System.Drawing.Color]::SteelBlue); $g.Dispose() |
| 254 | + $bmp.Save((Join-Path $layout "Assets/$logo.png"), [System.Drawing.Imaging.ImageFormat]::Png); $bmp.Dispose() |
| 255 | + } |
| 256 | + $kit = Get-ChildItem 'C:/Program Files (x86)/Windows Kits/10/bin/*/x64/makeappx.exe' | |
| 257 | + Sort-Object FullName -Descending | Select-Object -First 1 |
| 258 | + $bin = $kit.DirectoryName |
| 259 | + $msix = Join-Path $env:RUNNER_TEMP 'UwpSmoke.msix' |
| 260 | + & "$bin/makeappx.exe" pack /o /d $layout /p $msix |
| 261 | + if ($LASTEXITCODE -ne 0) { throw "makeappx failed" } |
| 262 | + # Signed with the certificate WindowsNativeBuilder created (subject |
| 263 | + # CN=UwpSmoke, the manifest Publisher; empty PKCS#12 password). |
| 264 | + $pfx = Join-Path $root 'uwp-smoke/devcert/dev.pfx' |
| 265 | + $cer = Join-Path $root 'uwp-smoke/devcert/dev.cer' |
| 266 | + & "$bin/signtool.exe" sign /fd SHA256 /f $pfx $msix |
| 267 | + if ($LASTEXITCODE -ne 0) { throw "signtool rejected the builder's development certificate" } |
| 268 | + Import-Certificate -FilePath $cer -CertStoreLocation 'Cert:/LocalMachine/TrustedPeople' | Out-Null |
| 269 | + $unlock = 'HKLM:/SOFTWARE/Microsoft/Windows/CurrentVersion/AppModelUnlock' |
| 270 | + New-Item -Force $unlock | Out-Null |
| 271 | + Set-ItemProperty $unlock AllowAllTrustedApps 1 -Type DWord |
| 272 | + Set-ItemProperty $unlock AllowDevelopmentWithoutDevLicense 1 -Type DWord |
| 273 | + Add-AppxPackage -Path $msix |
| 274 | + Get-AppxPackage com.codename1.uwpsmoke | Format-List Name,PackageFamilyName,InstallLocation,SignatureKind |
| 275 | +
|
| 276 | + - name: Launch and wait for the first frame |
| 277 | + shell: pwsh |
| 278 | + run: | |
| 279 | + $ErrorActionPreference = 'Stop' |
| 280 | + $pkg = Get-AppxPackage com.codename1.uwpsmoke |
| 281 | + $pfn = $pkg.PackageFamilyName |
| 282 | + $state = Join-Path $env:LOCALAPPDATA "Packages/$pfn/LocalState" |
| 283 | + Start-Process "shell:AppsFolder\$pfn!App" |
| 284 | + $marker = $null |
| 285 | + for ($i = 0; $i -lt 90 -and -not $marker; $i++) { |
| 286 | + Start-Sleep -Seconds 1 |
| 287 | + if (Test-Path $state) { |
| 288 | + $marker = Get-ChildItem -Recurse $state -Filter 'uwp-smoke.txt' -ErrorAction SilentlyContinue | Select-Object -First 1 |
| 289 | + } |
| 290 | + } |
| 291 | + Add-Type -AssemblyName System.Drawing, System.Windows.Forms |
| 292 | + $b = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds |
| 293 | + $bmp = New-Object System.Drawing.Bitmap $b.Width, $b.Height |
| 294 | + $g = [System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen($b.Location, [System.Drawing.Point]::Empty, $b.Size); $g.Dispose() |
| 295 | + New-Item -ItemType Directory -Force uwp-run | Out-Null |
| 296 | + $bmp.Save('uwp-run/desktop.png', [System.Drawing.Imaging.ImageFormat]::Png) |
| 297 | + Get-Process app -ErrorAction SilentlyContinue | Format-Table Id,ProcessName,StartTime |
| 298 | + if (-not $marker) { |
| 299 | + Get-WinEvent -LogName 'Microsoft-Windows-AppModel-Runtime/Admin' -MaxEvents 20 -ErrorAction SilentlyContinue | |
| 300 | + Format-List TimeCreated,Id,Message |
| 301 | + Get-WinEvent -FilterHashtable @{LogName='Application'; Id=1000,1001} -MaxEvents 5 -ErrorAction SilentlyContinue | |
| 302 | + Format-List TimeCreated,Message |
| 303 | + if (Test-Path $state) { Get-ChildItem -Recurse $state | Format-Table FullName,Length } |
| 304 | + throw "the UWP app wrote no marker in 90s: it did not reach its first frame" |
| 305 | + } |
| 306 | + $text = Get-Content $marker.FullName -Raw |
| 307 | + Write-Host "marker: $text" |
| 308 | + if ($text -notmatch '^CN1-UWP-STARTED [1-9][0-9]*x[1-9][0-9]*') { throw "unexpected marker: $text" } |
| 309 | + Get-Process app -ErrorAction SilentlyContinue | Stop-Process -Force |
| 310 | +
|
| 311 | + - name: Upload the desktop capture |
| 312 | + if: always() |
| 313 | + uses: actions/upload-artifact@v4 |
| 314 | + with: |
| 315 | + name: uwp-run-capture |
| 316 | + path: uwp-run/ |
| 317 | + if-no-files-found: ignore |
| 318 | + retention-days: 7 |
0 commit comments