Build and Test - Windows #6
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 Test - Windows" | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| build-type: | |
| description: 'Build type' | |
| required: true | |
| type: choice | |
| options: | |
| - debug | |
| - release | |
| default: release | |
| sign-build: | |
| description: 'Sign the build' | |
| required: true | |
| type: boolean | |
| default: true | |
| test-signing: | |
| description: 'Run pre-build signing test (optional)' | |
| required: false | |
| type: boolean | |
| default: false | |
| upload-artifacts: | |
| description: 'Upload build artifacts' | |
| required: true | |
| type: boolean | |
| default: true | |
| # Cancel duplicate workflow runs | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| RUST_BACKTRACE: 1 | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build-windows: | |
| name: Build Windows (x64) | |
| runs-on: windows-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version from tauri.conf.json | |
| id: get-version | |
| shell: bash | |
| run: | | |
| VERSION=$(grep -o '"version": "[^"]*"' frontend/src-tauri/tauri.conf.json | cut -d'"' -f4) | |
| echo "Application version: $VERSION" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| - name: Determine build profile | |
| id: build-profile | |
| shell: bash | |
| run: | | |
| if [[ "${{ github.event.inputs.build-type }}" == "debug" ]]; then | |
| echo "profile=debug" >> "$GITHUB_OUTPUT" | |
| echo "args=--debug" >> "$GITHUB_OUTPUT" | |
| echo "Build profile: debug" | |
| else | |
| echo "profile=release" >> "$GITHUB_OUTPUT" | |
| echo "args=" >> "$GITHUB_OUTPUT" | |
| echo "Build profile: release" | |
| fi | |
| - name: Setup DigiCert Environment | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| shell: pwsh | |
| run: | | |
| # Set environment variables | |
| "SM_HOST=${{ secrets.SM_HOST }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| "SM_API_KEY=${{ secrets.SM_API_KEY }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| "SM_CLIENT_CERT_PASSWORD=${{ secrets.SM_CLIENT_CERT_PASSWORD }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| "SM_CODE_SIGNING_CERT_SHA1_HASH=${{ secrets.SM_CODE_SIGNING_CERT_SHA1_HASH }}" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| # Decode and save client certificate using PowerShell | |
| $certPath = "D:\Certificate_pkcs12.p12" | |
| $base64String = "${{ secrets.SM_CLIENT_CERT_FILE_B64 }}" | |
| $certBytes = [System.Convert]::FromBase64String($base64String) | |
| [System.IO.File]::WriteAllBytes($certPath, $certBytes) | |
| # Verify the certificate file was created and has content | |
| if (Test-Path $certPath) { | |
| $certFile = Get-Item $certPath | |
| Write-Host "Certificate file created: $certPath" | |
| Write-Host " Size: $($certFile.Length) bytes" | |
| Write-Host " Last Modified: $($certFile.LastWriteTime)" | |
| # Verify it's a valid PKCS12 file by checking if we can load it | |
| try { | |
| $testCert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($certPath, "${{ secrets.SM_CLIENT_CERT_PASSWORD }}") | |
| Write-Host " ✓ Certificate file is valid PKCS12 format" | |
| Write-Host " ✓ Password is correct" | |
| Write-Host " Certificate Subject: $($testCert.Subject)" | |
| Write-Host " Certificate Thumbprint: $($testCert.Thumbprint)" | |
| } catch { | |
| Write-Warning "⚠ Certificate validation failed" | |
| Write-Warning "Error: $($_.Exception.Message)" | |
| Write-Warning "This may cause issues with signing, but we'll continue..." | |
| } | |
| } else { | |
| Write-Error "Certificate file was not created at $certPath" | |
| exit 1 | |
| } | |
| # Set the environment variable with Windows-style path | |
| "SM_CLIENT_CERT_FILE=D:\Certificate_pkcs12.p12" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| - name: Setup DigiCert KeyLocker | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| uses: digicert/ssm-code-signing@v1.1.1 | |
| - name: Sync Certificate to Windows Certificate Store | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| shell: pwsh | |
| run: | | |
| Write-Host "============================================================" | |
| Write-Host "=== SYNCING CERTIFICATE TO WINDOWS CERTIFICATE STORE ===" | |
| Write-Host "============================================================" | |
| Write-Host "This step syncs the DigiCert certificate from KeyLocker HSM" | |
| Write-Host "to the Windows Certificate Store (required for signing)" | |
| Write-Host "" | |
| # First, get the keypair alias from smctl keypair ls | |
| Write-Host "Retrieving keypair alias from DigiCert KeyLocker..." | |
| $keypairOutput = smctl keypair ls 2>&1 | Out-String | |
| Write-Host $keypairOutput | |
| # Extract the alias (looking for pattern like "key_XXXXXXXXXX") | |
| $aliasMatch = [regex]::Match($keypairOutput, 'key_\d+') | |
| if ($aliasMatch.Success) { | |
| $keypairAlias = $aliasMatch.Value | |
| Write-Host "✓ Found keypair alias: $keypairAlias" | |
| } else { | |
| Write-Error "✗ Could not find keypair alias in smctl output" | |
| Write-Error "Output was: $keypairOutput" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| Write-Host "Syncing certificate using alias: $keypairAlias" | |
| $certsyncOutput = smctl windows certsync --keypair-alias $keypairAlias 2>&1 | |
| Write-Host $certsyncOutput | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "" | |
| Write-Error "✗ Certificate sync FAILED" | |
| Write-Error "Exit code: $LASTEXITCODE" | |
| Write-Error "Output: $certsyncOutput" | |
| Write-Error "" | |
| Write-Error "Possible causes:" | |
| Write-Error " 1. Keypair alias '$keypairAlias' not found in KeyLocker" | |
| Write-Error " 2. Certificate is revoked or expired" | |
| Write-Error " 3. API credentials are invalid" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| Write-Host "✓ Certificate synced successfully" | |
| Write-Host "" | |
| # Verify certificate is now in Windows store | |
| Write-Host "Verifying certificate in Windows Certificate Store..." | |
| $cert = Get-ChildItem -Path Cert:\CurrentUser\My | Where-Object { $_.Thumbprint -eq $env:SM_CODE_SIGNING_CERT_SHA1_HASH } | Select-Object -First 1 | |
| if (-not $cert) { | |
| # Try LocalMachine store | |
| $cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Thumbprint -eq $env:SM_CODE_SIGNING_CERT_SHA1_HASH } | Select-Object -First 1 | |
| } | |
| if ($cert) { | |
| Write-Host "✓ Certificate found in Windows Certificate Store" | |
| Write-Host " Subject: $($cert.Subject)" | |
| Write-Host " Issuer: $($cert.Issuer)" | |
| Write-Host " Thumbprint: $($cert.Thumbprint)" | |
| Write-Host " Valid From: $($cert.NotBefore)" | |
| Write-Host " Valid Until: $($cert.NotAfter)" | |
| } else { | |
| Write-Warning "Certificate not found in Windows Certificate Store after sync" | |
| Write-Warning "Signing may fail. Continuing anyway..." | |
| } | |
| # Export keypair alias for Tauri signCommand | |
| Write-Host "" | |
| Write-Host "Exporting DIGICERT_KEYPAIR_ALIAS for Tauri signCommand..." | |
| "DIGICERT_KEYPAIR_ALIAS=$keypairAlias" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append | |
| Write-Host "✓ DIGICERT_KEYPAIR_ALIAS=$keypairAlias" | |
| Write-Host "" | |
| Write-Host "============================================================" | |
| Write-Host "" | |
| - name: Verify DigiCert Setup | |
| if: ${{ github.event.inputs.sign-build == 'true' }} | |
| shell: pwsh | |
| run: | | |
| Write-Host "=== DigiCert Setup Verification ===" | |
| Write-Host "" | |
| # Verify SMCTL is available | |
| Write-Host "SMCTL Version:" | |
| smctl --version | |
| Write-Host "" | |
| # Check environment variables | |
| Write-Host "Environment Variables:" | |
| Write-Host " SM_HOST: $env:SM_HOST" | |
| Write-Host " SM_API_KEY: $($env:SM_API_KEY.Substring(0, [Math]::Min(20, $env:SM_API_KEY.Length)))..." | |
| Write-Host " SM_CLIENT_CERT_FILE: $env:SM_CLIENT_CERT_FILE" | |
| Write-Host " SM_CLIENT_CERT_PASSWORD: $(if ($env:SM_CLIENT_CERT_PASSWORD) { '***SET***' } else { 'NOT SET' })" | |
| Write-Host "" | |
| # Verify client certificate file exists and check size | |
| if (Test-Path $env:SM_CLIENT_CERT_FILE) { | |
| $certFile = Get-Item $env:SM_CLIENT_CERT_FILE | |
| Write-Host "Client Certificate File:" | |
| Write-Host " Path: $($certFile.FullName)" | |
| Write-Host " Size: $($certFile.Length) bytes" | |
| Write-Host " Last Modified: $($certFile.LastWriteTime)" | |
| } else { | |
| Write-Error "Client certificate file NOT FOUND: $env:SM_CLIENT_CERT_FILE" | |
| } | |
| Write-Host "" | |
| # List available keypairs (verifies API authentication works) | |
| Write-Host "Available Keypairs:" | |
| smctl keypair ls | |
| Write-Host "" | |
| # Verify certificate (healthcheck) | |
| Write-Host "DigiCert Healthcheck:" | |
| smctl healthcheck | |
| Write-Host "" | |
| # Note: Healthcheck may show cert path/password warning but if keypair ls works, | |
| # the signing should still work. We'll test in the pre-build signing test. | |
| - name: Pre-Build Signing Test | |
| if: ${{ github.event.inputs.sign-build == 'true' && github.event.inputs.test-signing == 'true' }} | |
| shell: pwsh | |
| run: | | |
| Write-Host "============================================================" | |
| Write-Host "=== PRE-BUILD SIGNING TEST ===" | |
| Write-Host "============================================================" | |
| Write-Host "Testing signing before Tauri build to fail fast if signing is broken" | |
| Write-Host "" | |
| Write-Host "Environment Configuration:" | |
| Write-Host " SM_HOST: $($env:SM_HOST ?? 'NOT SET')" | |
| Write-Host " SM_API_KEY: $(if ($env:SM_API_KEY) { $env:SM_API_KEY.Substring(0, [Math]::Min(20, $env:SM_API_KEY.Length)) + '...' } else { 'NOT SET' })" | |
| Write-Host " SM_CLIENT_CERT_FILE: $($env:SM_CLIENT_CERT_FILE ?? 'NOT SET')" | |
| Write-Host " SM_CODE_SIGNING_CERT_SHA1_HASH: $($env:SM_CODE_SIGNING_CERT_SHA1_HASH ?? 'NOT SET')" | |
| # Verify environment is set up | |
| if (-not $env:SM_HOST -or -not $env:SM_API_KEY) { | |
| Write-Error "DigiCert environment not configured. Make sure 'Sign the build' is enabled." | |
| exit 1 | |
| } | |
| Write-Host "" | |
| # Verify client certificate exists | |
| if (Test-Path $env:SM_CLIENT_CERT_FILE) { | |
| Write-Host "✓ Client certificate file exists" | |
| $certInfo = Get-Item $env:SM_CLIENT_CERT_FILE | |
| Write-Host " File size: $($certInfo.Length) bytes" | |
| } else { | |
| Write-Error "✗ Client certificate file not found: $env:SM_CLIENT_CERT_FILE" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| Write-Host "--- Available Keypairs in DigiCert KeyLocker ---" | |
| $keypairOutput = smctl keypair ls 2>&1 | |
| Write-Host $keypairOutput | |
| Write-Host "" | |
| Write-Host "Note: Certificate was already synced to Windows Certificate Store in previous step" | |
| Write-Host "" | |
| # Create a minimal test executable using dotnet | |
| Write-Host "--- Creating Test Executable ---" | |
| Write-Host "Creating minimal C# console app..." | |
| # Create simple C# file | |
| $testCode = @" | |
| using System; | |
| class Program { | |
| static void Main() { | |
| Console.WriteLine("Test signing executable"); | |
| } | |
| } | |
| "@ | |
| Set-Content -Path "TestSigning.cs" -Value $testCode | |
| # Create minimal project file | |
| $projectFile = @" | |
| <Project Sdk="Microsoft.NET.Sdk"> | |
| <PropertyGroup> | |
| <OutputType>Exe</OutputType> | |
| <TargetFramework>net8.0</TargetFramework> | |
| </PropertyGroup> | |
| </Project> | |
| "@ | |
| Set-Content -Path "TestSigning.csproj" -Value $projectFile | |
| # Build executable in one command | |
| Write-Host "Building with dotnet publish..." | |
| dotnet publish TestSigning.csproj -c Release -o . --self-contained false 2>&1 | Out-Null | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Error "Failed to build test executable" | |
| Write-Host "Attempting to list dotnet info for debugging:" | |
| dotnet --version | |
| exit 1 | |
| } | |
| if (-not (Test-Path "TestSigning.exe")) { | |
| Write-Error "TestSigning.exe was not created" | |
| Get-ChildItem -Filter "*.exe" | Format-Table | |
| exit 1 | |
| } | |
| $exeInfo = Get-Item "TestSigning.exe" | |
| Write-Host "✓ Test executable compiled successfully" | |
| Write-Host " File: $($exeInfo.FullName)" | |
| Write-Host " Size: $($exeInfo.Length) bytes" | |
| # Verify unsigned state | |
| Write-Host "" | |
| Write-Host "--- Checking Unsigned State ---" | |
| $unsignedSig = Get-AuthenticodeSignature -FilePath "TestSigning.exe" | |
| Write-Host "Pre-signing status: $($unsignedSig.Status) (expected: NotSigned)" | |
| # Sign the test executable with signtool (certificate already in Windows store) | |
| Write-Host "" | |
| Write-Host "--- Signing Test Executable with SignTool ---" | |
| Write-Host "Certificate is already synced to Windows Certificate Store" | |
| Write-Host "Detecting certificate store location..." | |
| Write-Host "" | |
| # Extract keypair alias (needed for /k flag with /csp) | |
| $aliasMatch = [regex]::Match($keypairOutput, 'key_\d+') | |
| if ($aliasMatch.Success) { | |
| $keypairAlias = $aliasMatch.Value | |
| Write-Host "✓ Found keypair alias: $keypairAlias" | |
| } else { | |
| Write-Error "✗ Could not find keypair alias in smctl output" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| # Detect which store the certificate is in | |
| $certCurrentUser = Get-ChildItem -Path Cert:\CurrentUser\My -ErrorAction SilentlyContinue | Where-Object { $_.Thumbprint -eq $env:SM_CODE_SIGNING_CERT_SHA1_HASH } | Select-Object -First 1 | |
| $certLocalMachine = Get-ChildItem -Path Cert:\LocalMachine\My -ErrorAction SilentlyContinue | Where-Object { $_.Thumbprint -eq $env:SM_CODE_SIGNING_CERT_SHA1_HASH } | Select-Object -First 1 | |
| $storeFlag = "" | |
| $storeName = "" | |
| if ($certCurrentUser) { | |
| Write-Host "✓ Certificate found in CurrentUser\My store" | |
| $storeFlag = "/s My" | |
| $storeName = "CurrentUser\My" | |
| } elseif ($certLocalMachine) { | |
| Write-Host "✓ Certificate found in LocalMachine\My store" | |
| $storeFlag = "/sm /s My" | |
| $storeName = "LocalMachine\My" | |
| } else { | |
| Write-Error "✗ Certificate not found in CurrentUser\My or LocalMachine\My stores" | |
| Write-Error "SHA1 hash: $env:SM_CODE_SIGNING_CERT_SHA1_HASH" | |
| exit 1 | |
| } | |
| Write-Host "Using store: $storeName" | |
| Write-Host "SHA1 hash: $env:SM_CODE_SIGNING_CERT_SHA1_HASH" | |
| Write-Host "Keypair alias: $keypairAlias" | |
| Write-Host "" | |
| # Test using the exact same command as tauri.conf.json signCommand | |
| Write-Host "Testing sign-windows.ps1 script (same as Tauri signCommand)..." | |
| Write-Host "Command: powershell -ExecutionPolicy Bypass -File frontend/src-tauri/scripts/sign-windows.ps1 -FilePath TestSigning.exe" | |
| Write-Host "" | |
| # Set DIGICERT_KEYPAIR_ALIAS for the script (already exported to GITHUB_ENV, but set locally too) | |
| $env:DIGICERT_KEYPAIR_ALIAS = $keypairAlias | |
| $signOutput = powershell -ExecutionPolicy Bypass -File "frontend/src-tauri/scripts/sign-windows.ps1" -FilePath "TestSigning.exe" 2>&1 | |
| Write-Host $signOutput | |
| if ($LASTEXITCODE -ne 0) { | |
| Write-Host "" | |
| Write-Host "============================================================" | |
| Write-Error "✗✗✗ SIGNING FAILED ✗✗✗" | |
| Write-Host "============================================================" | |
| Write-Error "Exit code: $LASTEXITCODE" | |
| Write-Error "Script output: $signOutput" | |
| Write-Error "" | |
| Write-Error "Certificate was found in: $storeName" | |
| Write-Error "DIGICERT_KEYPAIR_ALIAS: $keypairAlias" | |
| Write-Error "" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| Write-Host "✓ Test executable signed successfully using sign-windows.ps1" | |
| # Verify the signature | |
| Write-Host "" | |
| Write-Host "--- Verifying Signature ---" | |
| $signature = Get-AuthenticodeSignature -FilePath "TestSigning.exe" | |
| Write-Host "Signature Details:" | |
| Write-Host " Status: $($signature.Status)" | |
| Write-Host " Status Message: $($signature.StatusMessage)" | |
| Write-Host " Signer Certificate:" | |
| Write-Host " Subject: $($signature.SignerCertificate.Subject)" | |
| Write-Host " Issuer: $($signature.SignerCertificate.Issuer)" | |
| Write-Host " Thumbprint: $($signature.SignerCertificate.Thumbprint)" | |
| Write-Host " Valid From: $($signature.SignerCertificate.NotBefore)" | |
| Write-Host " Valid To: $($signature.SignerCertificate.NotAfter)" | |
| if ($signature.TimeStamperCertificate) { | |
| Write-Host " Timestamp Certificate:" | |
| Write-Host " Subject: $($signature.TimeStamperCertificate.Subject)" | |
| Write-Host " Issuer: $($signature.TimeStamperCertificate.Issuer)" | |
| } | |
| # Validate signature | |
| if ($signature.Status -ne 'Valid') { | |
| Write-Host "" | |
| Write-Host "============================================================" | |
| Write-Error "✗✗✗ SIGNATURE VERIFICATION FAILED ✗✗✗" | |
| Write-Host "============================================================" | |
| Write-Error "Expected Status: Valid" | |
| Write-Error "Actual Status: $($signature.Status)" | |
| Write-Error "Status Message: $($signature.StatusMessage)" | |
| exit 1 | |
| } | |
| if (-not $signature.TimeStamperCertificate) { | |
| Write-Host "" | |
| Write-Host "============================================================" | |
| Write-Error "✗✗✗ MISSING TIMESTAMP ✗✗✗" | |
| Write-Host "============================================================" | |
| Write-Error "Timestamp certificate is missing!" | |
| Write-Error "Without timestamp, signature will become invalid when cert expires" | |
| exit 1 | |
| } | |
| Write-Host "" | |
| Write-Host "✓ Signature verified successfully" | |
| Write-Host "✓ Timestamp present" | |
| Write-Host "" | |
| Write-Host "--- Cleanup ---" | |
| Remove-Item "TestSigning.exe" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.cs" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.csproj" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.dll" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.pdb" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.deps.json" -ErrorAction SilentlyContinue | |
| Remove-Item "TestSigning.runtimeconfig.json" -ErrorAction SilentlyContinue | |
| Write-Host "✓ Test files cleaned up" | |
| Write-Host "" | |
| Write-Host "============================================================" | |
| Write-Host "=== PRE-BUILD SIGNING TEST PASSED ===" | |
| Write-Host "============================================================" | |
| Write-Host "Signing infrastructure is working correctly" | |
| Write-Host "Proceeding with Tauri build..." | |
| Write-Host "" | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 8 | |
| run_install: false | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-msvc | |
| - name: Rust cache | |
| uses: swatinem/rust-cache@v2 | |
| with: | |
| workspaces: ". -> target" | |
| key: windows-x64-vulkan-v2 | |
| - name: Install Vulkan SDK | |
| uses: humbletim/install-vulkan-sdk@v1.2 | |
| with: | |
| version: 1.4.309.0 | |
| cache: true | |
| - name: Copy Vulkan runtime for bundling | |
| shell: pwsh | |
| run: | | |
| # Create runtime directory | |
| $runtimeDir = "frontend/src-tauri/vulkan-runtime" | |
| if (!(Test-Path $runtimeDir)) { | |
| New-Item -ItemType Directory -Force -Path $runtimeDir | Out-Null | |
| } | |
| # Copy Vulkan loader DLL from SDK | |
| $vulkanSdk = $env:VULKAN_SDK | |
| Write-Host "Vulkan SDK path: $vulkanSdk" | |
| $vulkanDll = "$vulkanSdk\Bin\vulkan-1.dll" | |
| if (Test-Path $vulkanDll) { | |
| Copy-Item $vulkanDll -Destination $runtimeDir | |
| Write-Host "Copied vulkan-1.dll to $runtimeDir" | |
| } else { | |
| Write-Warning "vulkan-1.dll not found at $vulkanDll" | |
| } | |
| # Verify | |
| Write-Host "Contents of vulkan-runtime directory:" | |
| Get-ChildItem $runtimeDir | |
| - name: Install frontend dependencies | |
| run: | | |
| cd frontend | |
| pnpm install | |
| - name: Build llama-helper sidecar | |
| shell: bash | |
| run: | | |
| echo "Building llama-helper sidecar with Vulkan support..." | |
| cargo build --release -p llama-helper --features vulkan | |
| # Copy binary to binaries directory | |
| mkdir -p frontend/src-tauri/binaries | |
| cp target/release/llama-helper.exe frontend/src-tauri/binaries/llama-helper-x86_64-pc-windows-msvc.exe | |
| echo "Copied llama-helper to frontend/src-tauri/binaries/" | |
| ls -la frontend/src-tauri/binaries/ | |
| - name: Build Tauri app | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Tauri updater signing (ALWAYS enabled for .sig files) | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| # License validation RSA public key (embedded at build time) | |
| MEETILY_RSA_PUBLIC_KEY: ${{ secrets.MEETILY_RSA_PUBLIC_KEY }} | |
| # Supabase configuration (for online license verification) | |
| SUPABASE_URL: ${{ secrets.SUPABASE_URL }} | |
| SUPABASE_ANON_KEY: ${{ secrets.SUPABASE_ANON_KEY }} | |
| with: | |
| projectPath: frontend | |
| args: --target x86_64-pc-windows-msvc --features vulkan ${{ steps.build-profile.outputs.args }} | |
| - name: Verify build artifacts | |
| shell: bash | |
| run: | | |
| echo "## Build Artifacts" | |
| find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle -type f \( -name "*.msi" -o -name "*.exe" \) -exec ls -lh {} \; | |
| - name: Upload artifacts | |
| if: ${{ github.event.inputs.upload-artifacts == 'true' }} | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: meetily-windows-x64-${{ steps.build-profile.outputs.profile }}-${{ steps.get-version.outputs.version }} | |
| path: | | |
| target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/msi/*.msi | |
| target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/msi/*.msi.sig | |
| target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/nsis/*.exe | |
| target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/nsis/*.exe.sig | |
| retention-days: 30 | |
| - name: Generate build summary | |
| shell: bash | |
| run: | | |
| echo "## 🪟 Windows Build Summary" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Version** | ${{ steps.get-version.outputs.version }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Build Profile** | ${{ steps.build-profile.outputs.profile }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Target** | x86_64-pc-windows-msvc |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Signed** | ${{ (github.event.inputs.sign-build == 'true') && '✅ Yes' || '❌ No' }} |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "### 📦 Build Artifacts" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| File Type | Count |" >> $GITHUB_STEP_SUMMARY | |
| echo "|-----------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| MSI Installers | $(find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/msi -name "*.msi" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| MSI Signatures | $(find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/msi -name "*.msi.sig" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| NSIS Installers | $(find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/nsis -name "*.exe" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "| NSIS Signatures | $(find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle/nsis -name "*.exe.sig" 2>/dev/null | wc -l) |" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "<details>" >> $GITHUB_STEP_SUMMARY | |
| echo "<summary>📋 File List</summary>" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| find target/x86_64-pc-windows-msvc/${{ steps.build-profile.outputs.profile }}/bundle -type f \( -name "*.msi" -o -name "*.exe" -o -name "*.sig" \) 2>/dev/null >> $GITHUB_STEP_SUMMARY | |
| echo "\`\`\`" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "</details>" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY |