jac-gpt-fullstack Integration Test #732
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: jac-gpt-fullstack Integration Test | |
| on: | |
| schedule: | |
| - cron: '0 0,6,12,18 * * *' | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - 'jac-gpt-fullstack/**' | |
| - '.github/workflows/jac-gpt-integration-test.yml' | |
| pull_request: | |
| branches: | |
| - main | |
| paths: | |
| - 'jac-gpt-fullstack/**' | |
| - '.github/workflows/jac-gpt-integration-test.yml' | |
| workflow_dispatch: | |
| inputs: | |
| jac_release: | |
| description: 'jaseci release tag to test against (dev = rolling build of main)' | |
| required: false | |
| default: 'dev' | |
| permissions: | |
| contents: read | |
| jobs: | |
| integration-test: | |
| name: Server Start Test (jaseci dev/main) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout Agentic-AI | |
| uses: actions/checkout@v4 | |
| - name: Set up Node.js 20 | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Set up Bun | |
| uses: oven-sh/setup-bun@v2 | |
| # jaclang ships as a self-contained native binary (bundled CPython + bun), | |
| # not a pip package, so there is nothing to `pip install`. The `dev` release | |
| # is a prebuilt rolling build of main -- download it directly (seconds) | |
| # instead of compiling from source with Zig (~34 min cold on every run, | |
| # since a cross-repo cache goes cold whenever jaseci touches jaclang). | |
| - name: Install jac binary (prebuilt dev build of main) | |
| env: | |
| JAC_RELEASE: ${{ github.event.inputs.jac_release || 'dev' }} | |
| run: | | |
| set -euo pipefail | |
| ASSET="jac-${JAC_RELEASE}-linux-x86_64" | |
| BASE="https://github.com/jaseci-labs/jaseci/releases/download/${JAC_RELEASE}" | |
| mkdir -p "$HOME/.jacbin" | |
| cd "$HOME/.jacbin" | |
| echo "Downloading ${ASSET} from ${BASE}..." | |
| curl -fsSL -o "${ASSET}" "${BASE}/${ASSET}" | |
| curl -fsSL -o "${ASSET}.sha256" "${BASE}/${ASSET}.sha256" | |
| sha256sum -c "${ASSET}.sha256" | |
| mv "${ASSET}" jac | |
| chmod +x jac | |
| echo "$HOME/.jacbin" >> "$GITHUB_PATH" | |
| # The binary bundles jaclang (incl. the folded-in client + byllm + scale), | |
| # but the heavy runtime capability closures install separately, exactly as | |
| # jaseci's own CI does. Pins mirror jac/jaclang/project/capabilities.jac. | |
| - name: Install serve capability deps (for `jac start`) | |
| run: | | |
| jac install \ | |
| "fastapi>=0.121.3,<0.122.0" "uvicorn[standard]>=0.38.0,<0.39.0" \ | |
| "pyjwt>=2.10.1,<2.11.0" "fastapi-sso>=0.21.0,<1.0.0" \ | |
| "python-multipart>=0.0.21,<1.0.0" "bcrypt>=4.0.0,<5.0.0" \ | |
| "aiohttp>=3.9.0,<4.0.0" "sqlalchemy>=2.0.0,<3.0.0" \ | |
| "email-validator>=2.3.0,<3.0.0" "python-dotenv>=1.2.1,<2.0.0" \ | |
| "requests>=2.32.0,<3.0.0" \ | |
| --global | |
| - name: Install byllm capability deps (for `by llm()`) | |
| run: | | |
| jac install \ | |
| "litellm>=1.70.0,<=1.82.6" "pillow>=12.0.0,<13.0.0" \ | |
| "httpx>=0.27.0" "loguru>=0.7.2,<0.8.0" \ | |
| --global | |
| - name: Install app dependencies | |
| working-directory: jac-gpt-fullstack | |
| run: jac install | |
| - name: Restore FAISS index cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: jac-gpt-fullstack/services/faiss_index | |
| key: jac-gpt-faiss-v1 | |
| - name: Install Playwright dependencies | |
| # --global puts playwright in the binary's own site so the e2e (run from | |
| # the project dir) can import it; a plain install would land in the | |
| # project venv instead. | |
| run: | | |
| jac install playwright --global | |
| jac -m playwright install chromium --with-deps | |
| - name: Verify installation | |
| run: | | |
| echo "=== Jac Version ===" | |
| jac --version | |
| echo "=== Plugins ===" | |
| jac plugins list | |
| JAC_VERSION="$(jac --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" | |
| echo "JAC_VERSION=${JAC_VERSION:-unknown}" >> "$GITHUB_ENV" | |
| - name: Run jac check | |
| working-directory: jac-gpt-fullstack | |
| run: jac check main.jac | |
| - name: Start server in background | |
| working-directory: jac-gpt-fullstack | |
| env: | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} | |
| MODEL: gemini/gemini-2.0-flash | |
| run: | | |
| timeout 600 jac start main.jac > /tmp/jac-server.log 2>&1 & | |
| SERVER_PID=$! | |
| echo "SERVER_PID=$SERVER_PID" >> $GITHUB_ENV | |
| echo "Server starting with PID $SERVER_PID..." | |
| sleep 10 | |
| if ! kill -0 $SERVER_PID 2>/dev/null; then | |
| echo "Server process died during startup" | |
| cat /tmp/jac-server.log | |
| exit 1 | |
| fi | |
| - name: Wait for server to be ready | |
| run: | | |
| echo "Waiting for server on port 8000..." | |
| for i in $(seq 1 24); do | |
| if ! kill -0 ${{ env.SERVER_PID }} 2>/dev/null; then | |
| echo "Server process exited unexpectedly" | |
| cat /tmp/jac-server.log | |
| exit 1 | |
| fi | |
| if curl -sf --max-time 10 http://localhost:8000 -o /dev/null 2>/dev/null; then | |
| echo "Server is ready (attempt $i)" | |
| exit 0 | |
| fi | |
| echo "Attempt $i/24: not ready, waiting 15s..." | |
| sleep 15 | |
| done | |
| echo "Server failed to respond after 24 attempts" | |
| tail -100 /tmp/jac-server.log | |
| exit 1 | |
| - name: Verify HTTP response | |
| run: | | |
| HTTP_CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 http://localhost:8000) | |
| echo "Root endpoint: HTTP $HTTP_CODE" | |
| if [ "$HTTP_CODE" -ge 200 ] && [ "$HTTP_CODE" -lt 500 ]; then | |
| echo "Server responding correctly" | |
| else | |
| echo "Unexpected HTTP $HTTP_CODE" | |
| exit 1 | |
| fi | |
| - name: Run E2E tests | |
| working-directory: jac-gpt-fullstack | |
| env: | |
| SERVER_URL: http://localhost:8000 | |
| # Run from the project dir so the binary loads jac-gpt's deps; the binary | |
| # provides jaclang + pytest (system pytest has neither). | |
| run: jac test tests/test_e2e.jac -vv | |
| - name: Stop server | |
| if: always() | |
| run: | | |
| if [ -n "${{ env.SERVER_PID }}" ]; then | |
| kill ${{ env.SERVER_PID }} 2>/dev/null || true | |
| sleep 3 | |
| kill -9 ${{ env.SERVER_PID }} 2>/dev/null || true | |
| fi | |
| - name: Upload server logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: jac-server-logs | |
| path: /tmp/jac-server.log | |
| retention-days: 7 | |
| - name: Upload E2E screenshots | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: e2e-screenshots | |
| path: jac-gpt-fullstack/tests/screenshots/ | |
| retention-days: 7 | |
| - name: Job summary | |
| if: always() | |
| run: | | |
| echo "## jac-gpt-fullstack Integration Test" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "| Detail | Value |" >> $GITHUB_STEP_SUMMARY | |
| echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Jac version** | \`${{ env.JAC_VERSION }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **jac release** | \`${{ github.event.inputs.jac_release || 'dev' }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Status** | \`${{ job.status }}\` |" >> $GITHUB_STEP_SUMMARY | |
| echo "| **Trigger** | \`${{ github.event_name }}\` |" >> $GITHUB_STEP_SUMMARY |