Skip to content

[#509] Cross-platform stormtest + serve-this-worktree pathing #1125

[#509] Cross-platform stormtest + serve-this-worktree pathing

[#509] Cross-platform stormtest + serve-this-worktree pathing #1125

Workflow file for this run

name: CI
on:
workflow_dispatch:
push:
branches: [main, beta]
pull_request:
branches: [main, beta]
## Stop CI from injecting fake "installs" into the telemetry dashboard or
## burning streaming-insert quota on the backend. Opt-out is fully
## side-effect-free in the collector (no UUID generated, no worker
## thread, no _send), so the test/runtime behavior under this flag
## matches a real opted-out end-user install. Mirrored in script/ci-*
## shell scripts for any path that doesn't inherit this env.
env:
GODOT_AI_DISABLE_TELEMETRY: "true"
jobs:
python-tests:
name: Python ${{ matrix.python-version }} / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Deliberately Linux-only: the Python server is pure-async with no
# platform-specific code. Real OS regressions are caught by the
# release-smoke and godot-tests jobs, which still run on all 3 OSes.
# See issue #35 before restoring the full matrix.
os: [ubuntu-latest]
python-version: ["3.11", "3.13"]
steps:
- uses: actions/checkout@v6
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
with:
python-version: ${{ matrix.python-version }}
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Run tests
run: pytest -v
- name: Run tests with coverage
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
run: pytest --cov=godot_ai --cov-report=xml -v
- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.13'
uses: codecov/codecov-action@v6
with:
files: ./coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
- name: Lint
run: ruff check src/ tests/
release-smoke:
name: Release smoke / ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Build sdist and wheel
run: |
python -m pip install --upgrade pip build
python -m build
- name: Install built wheel in a clean venv
shell: bash
run: |
venv="${RUNNER_TEMP}/smoke-venv"
python -m venv "$venv"
if [ -x "$venv/bin/python" ]; then
PY="$venv/bin/python"
GODOT_AI="$venv/bin/godot-ai"
else
PY="$venv/Scripts/python.exe"
GODOT_AI="$venv/Scripts/godot-ai.exe"
fi
# Use `python -m pip` rather than the pip executable — on Windows,
# pip.exe can't replace itself mid-upgrade, which breaks smoke tests.
"$PY" -m pip install dist/*.whl
"$GODOT_AI" --version
"$GODOT_AI" --help
- name: Install built sdist in a clean venv
shell: bash
run: |
venv="${RUNNER_TEMP}/smoke-sdist-venv"
python -m venv "$venv"
if [ -x "$venv/bin/python" ]; then
PY="$venv/bin/python"
GODOT_AI="$venv/bin/godot-ai"
else
PY="$venv/Scripts/python.exe"
GODOT_AI="$venv/Scripts/godot-ai.exe"
fi
"$PY" -m pip install dist/*.tar.gz
"$GODOT_AI" --version
- name: Upload build artifacts
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v7
with:
name: dist
path: dist/
godot-tests:
name: Godot tests / ${{ matrix.label }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
label: Linux
godot-version: "4.6.2"
- os: macos-latest
label: macOS
godot-version: "4.6.2"
- os: windows-latest
label: Windows
godot-version: "4.6.2"
## 4.3 Linux canary — README advertises "Godot 4.3+" support and
## #476's parse-cascade regression went unnoticed for 24 days
## because every CI run was on 4.6.2. Phase 1 of #477: one cheap
## Linux canary to catch the same class of regression in future.
## Phase 2 (full 3-OS 4.3 coverage) is deferred.
- os: ubuntu-latest
label: Linux (Godot 4.3)
godot-version: "4.3.0"
steps:
- uses: actions/checkout@v6
- name: Build plugin link
shell: bash
run: bash script/verify-worktree
- uses: chickensoft-games/setup-godot@v2
with:
version: ${{ matrix.godot-version }}
use-dotnet: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Self-update forward upgrade regression
shell: bash
timeout-minutes: 3
run: GODOT_BIN=godot pytest -q tests/integration/test_self_update_upgrade_paths.py
- name: Start MCP server
shell: bash
run: bash script/ci-start-server
- name: Import and validate GDScript
shell: bash
timeout-minutes: 3
run: |
godot --headless --path test_project --import > godot-import.log 2>&1 || true
bash script/ci-check-gdscript godot-import.log
- name: Start Godot editor (headless)
shell: bash
run: GODOT_AI_ALLOW_HEADLESS=1 godot --headless --path test_project --editor > godot-editor.log 2>&1 &
- name: Run handler tests
shell: bash
timeout-minutes: 3
run: bash script/ci-godot-tests
- name: Reload smoke test
shell: bash
timeout-minutes: 2
## On the 4.3 canary, skip only the post-churn test_run step:
## GDScript exec is slow enough on 4.3 that the suite outruns
## mcp_call's 30s curl timeout, even though the 10 reload
## iterations themselves all pass. The reload-churn mechanism
## is the regression class this smoke guards, so the canary
## still has value.
env:
SKIP_POSTCHURN_TEST_RUN: ${{ matrix.godot-version == '4.3.0' && '1' || '0' }}
run: bash script/ci-reload-test
- name: Quit smoke test
shell: bash
timeout-minutes: 2
run: bash script/ci-quit-test
- name: Dump Godot editor log on failure
if: failure()
shell: bash
run: |
echo "===== godot-editor.log (last 500 lines) ====="
tail -n 500 godot-editor.log || echo "(log not found)"
echo "===== godot-import.log (last 200 lines) ====="
tail -n 200 godot-import.log || echo "(log not found)"
# Verifies the plugin's automatic kill+respawn flow when port 8000 is held
# by a stale godot-ai server (different version). The unit tests in
# test_plugin_lifecycle.gd mock every OS interaction; this is the only
# automated job that exercises the real per-OS branded-kill machinery
# (PowerShell on Windows, /proc on Linux, ps on macOS). Replaces the
# manual operator runs of `script/manual-orphan-test`.
stale-server-smoke:
name: Stale server smoke / ${{ matrix.label }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
label: Linux
- os: macos-latest
label: macOS
- os: windows-latest
label: Windows
steps:
- uses: actions/checkout@v6
- name: Build plugin link
shell: bash
run: bash script/verify-worktree
- uses: chickensoft-games/setup-godot@v2
with:
version: 4.6.2
use-dotnet: false
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Import and validate GDScript
shell: bash
timeout-minutes: 3
run: |
godot --headless --path test_project --import > godot-import.log 2>&1 || true
bash script/ci-check-gdscript godot-import.log
- name: Run stale-server smoke
shell: bash
timeout-minutes: 3
run: python script/ci-stale-server-smoke --log-dir .
- name: Dump editor log on failure
if: failure()
shell: bash
run: |
echo "===== godot-stale-smoke.log (last 500 lines) ====="
tail -n 500 godot-stale-smoke.log || echo "(log not found)"
echo "===== godot-import.log (last 200 lines) ====="
tail -n 200 godot-import.log || echo "(log not found)"
# Separate job from godot-tests: the capture smoke test needs a real
# rendering driver (null RenderingDevice in --headless produces empty
# framebuffers) and a display server. Linux uses xvfb-run; macOS and
# Windows CI runners have a real graphics stack and run the editor
# windowed. This job verifies editor_screenshot(source="game") round-
# trips real game pixels — see closes #72.
game-capture-smoke:
name: Game capture smoke / ${{ matrix.label }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
label: Linux
- os: macos-latest
label: macOS
- os: windows-latest
label: Windows
steps:
- uses: actions/checkout@v6
- name: Build plugin link
shell: bash
run: bash script/verify-worktree
- uses: chickensoft-games/setup-godot@v2
with:
version: 4.6.2
use-dotnet: false
- name: Install xvfb
if: matrix.os == 'ubuntu-latest'
run: sudo apt-get update && sudo apt-get install -y xvfb
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.13"
cache: pip
cache-dependency-path: pyproject.toml
- name: Install dependencies
run: pip install -e ".[dev]"
- name: Start MCP server
shell: bash
run: bash script/ci-start-server
- name: Import and validate GDScript
shell: bash
timeout-minutes: 3
run: |
godot --headless --path test_project --import > godot-import.log 2>&1 || true
bash script/ci-check-gdscript godot-import.log
- name: Start Godot editor (Linux / xvfb)
if: matrix.os == 'ubuntu-latest'
shell: bash
run: |
xvfb-run -a --server-args="-screen 0 1280x720x24" \
godot --rendering-driver opengl3 --path test_project --editor &
- name: Start Godot editor (windowed)
if: matrix.os != 'ubuntu-latest'
shell: bash
run: godot --path test_project --editor &
- name: Run capture smoke test
timeout-minutes: 5
shell: bash
run: python script/ci-game-capture-smoke