Repository navigation
fix(ci): robust smoke test polling + launcher startup hardening #2
Workflow file for this run
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
| # ============================================================================= | |
| # Build panelagent.exe on tag push and attach it to a GitHub Release. | |
| # ============================================================================= | |
| # Trigger: push a tag matching v* (e.g. v1.0.0). The workflow builds the | |
| # static frontend, bundles it with the Python backend via PyInstaller on a | |
| # Windows runner, and uploads panelagent.exe to a Release for that tag. | |
| # ============================================================================= | |
| name: Build Windows exe | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: # allow manual runs from the Actions tab | |
| permissions: | |
| contents: write # required to create the release and upload the asset | |
| jobs: | |
| build: | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.13" | |
| - name: Set up Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install backend deps + PyInstaller | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r backend/requirements.txt | |
| pip install pyinstaller | |
| - name: Build static frontend | |
| env: | |
| NEXT_PUBLIC_API_URL: "http://127.0.0.1:8000" | |
| run: | | |
| cd frontend | |
| npm install | |
| npm run build | |
| if (-Not (Test-Path "out/index.html")) { throw "next build did not produce out/index.html" } | |
| shell: pwsh | |
| - name: Build exe | |
| run: | | |
| python -m PyInstaller panelagent.spec --noconfirm --clean | |
| if (-Not (Test-Path "dist/panelagent.exe")) { throw "PyInstaller did not produce dist/panelagent.exe" } | |
| shell: pwsh | |
| - name: Smoke test (start exe + poll health endpoint + kill) | |
| continue-on-error: true # don't block the release upload if the CI env can't reach localhost | |
| run: | | |
| Write-Host "Launching dist\panelagent.exe..." | |
| $p = Start-Process -FilePath "dist\panelagent.exe" -PassThru | |
| # PyInstaller one-file cold start: unpack bundle + import pandas/scipy | |
| # can take 30-60s on first run. Poll up to 120s. | |
| $ok = $false | |
| for ($i = 0; $i -lt 24; $i++) { | |
| Start-Sleep -Seconds 5 | |
| try { | |
| $resp = Invoke-WebRequest -Uri "http://127.0.0.1:8000/api/v1/health" -UseBasicParsing -TimeoutSec 5 | |
| if ($resp.StatusCode -eq 200) { | |
| Write-Host "Health check OK after $($i*5)s: $($resp.Content)" | |
| $ok = $true | |
| break | |
| } | |
| } catch { | |
| Write-Host "Waiting... ($($_.Exception.Message.Split([Environment]::NewLine)[0]))" | |
| } | |
| } | |
| Stop-Process -Id $p.Id -Force -ErrorAction SilentlyContinue | |
| # Wait for child processes (uvicorn workers) to exit. | |
| Start-Sleep -Seconds 2 | |
| if (-not $ok) { | |
| Write-Host "::warning::Smoke test could not reach health endpoint within 120s. The exe will still be uploaded so users can test manually." | |
| } | |
| shell: pwsh | |
| - name: Get version from tag | |
| if: startsWith(github.ref, 'refs/tags/') | |
| id: version | |
| run: echo "tag=${GITHUB_REF#refs/tags/}" >> $env:GITHUB_OUTPUT | |
| shell: pwsh | |
| - name: Create / update Release and upload asset | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.version.outputs.tag || github.ref_name }} | |
| name: PanelAgent ${{ steps.version.outputs.tag || 'dev' }} | |
| files: dist/panelagent.exe | |
| generate_release_notes: true | |
| fail_on_unmatched_files: true |