Skip to content

build(deps): bump hono from 4.12.18 to 4.12.23 in /plugins/home-assistant-dev/mcp-server #137

build(deps): bump hono from 4.12.18 to 4.12.23 in /plugins/home-assistant-dev/mcp-server

build(deps): bump hono from 4.12.18 to 4.12.23 in /plugins/home-assistant-dev/mcp-server #137

name: HA Dev Plugin Tests
on:
push:
branches: [main, testing]
paths:
- "plugins/home-assistant-dev/**"
pull_request:
branches: [main]
paths:
- "plugins/home-assistant-dev/**"
defaults:
run:
working-directory: plugins/home-assistant-dev
jobs:
python-tests:
name: Python Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install pytest pytest-asyncio pytest-cov pyyaml
- name: Run unit tests
run: python3 -m pytest tests/scripts/ -v -m unit --tb=short --cov=scripts --cov-report=term-missing
- name: Run validation tests
run: python3 -m pytest tests/validation/ -v --tb=short
- name: Run structural tests
run: python3 -m pytest tests/test_plugin_structure.py -v --tb=short
integration-tests:
name: Script Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Run scripts against examples
run: bash tests/integration/test_scripts_against_examples.sh
- name: Validate example manifests
run: |
for example in polling-hub minimal-sensor push-integration; do
echo "Validating $example..."
python3 scripts/validate-manifest.py \
examples/$example/custom_components/*/manifest.json
done
typescript-tests:
name: TypeScript Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: plugins/home-assistant-dev/mcp-server
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "20"
cache: "npm"
cache-dependency-path: plugins/home-assistant-dev/mcp-server/package-lock.json
- name: Install dependencies
run: npm ci
- name: Type check
run: npm run typecheck
- name: Run tests with coverage
run: npm run test:coverage
- name: Build
run: npm run build
structural-validation:
name: Plugin Structure
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install dependencies
run: pip install pytest pyyaml
- name: Validate plugin structure
run: python3 -m pytest tests/test_plugin_structure.py -v --tb=long
- name: Validate skill frontmatter
run: |
for skill in skills/*/SKILL.md; do
head -1 "$skill" | grep -q '^---' || { echo "FAIL: $skill missing frontmatter"; exit 1; }
done
echo "All skill frontmatters valid"
- name: Validate hooks.json
run: python3 -c "import json; json.load(open('hooks/hooks.json')); print('hooks.json valid')"
mcp-e2e-tests:
name: MCP E2E Tests (HA Container)
runs-on: ubuntu-latest
# Only run on main branch merges or when explicitly labeled
if: github.ref == 'refs/heads/main' || contains(github.event.pull_request.labels.*.name, 'run-e2e')
services:
homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable
ports:
- 8123:8123
options: >-
--health-cmd "curl -sf http://localhost:8123/ -o /dev/null || exit 1" --health-interval 5s --health-timeout 3s --health-retries 60 --health-start-period 60s
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: "20"
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install aiohttp
cd mcp-server && npm ci
- name: Write HA configuration
run: |
# The HA service container needs configuration
# Since we can't easily mount files, use the API after onboarding
echo "HA container starting..."
- name: Complete HA onboarding
run: |
set -e
HA_BASE="http://localhost:8123"
# Wait for HA to be fully ready (healthcheck may pass before onboarding is available)
for i in $(seq 1 30); do
if curl -sf "$HA_BASE/api/onboarding/users" -X POST \
-H "Content-Type: application/json" \
-d '{"client_id":"'"$HA_BASE"'/","name":"Test","username":"test","password":"test1234","language":"en"}' \
> /tmp/ha-onboard.json 2>/dev/null; then
break
fi
echo "Waiting for onboarding endpoint... ($i/30)"
sleep 5
done
AUTH_CODE=$(python3 -c "import json; print(json.load(open('/tmp/ha-onboard.json'))['auth_code'])")
curl -sf -X POST "$HA_BASE/auth/token" \
-d "grant_type=authorization_code&code=$AUTH_CODE&client_id=$HA_BASE/" \
> /tmp/ha-tokens.json
ACCESS_TOKEN=$(python3 -c "import json; print(json.load(open('/tmp/ha-tokens.json'))['access_token'])")
curl -sf -X POST "$HA_BASE/api/onboarding/core_config" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" -d '{}'
curl -sf -X POST "$HA_BASE/api/onboarding/analytics" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" -d '{}'
curl -sf -X POST "$HA_BASE/api/onboarding/integration" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"client_id":"'"$HA_BASE"'/","redirect_uri":"'"$HA_BASE"'/"}'
# Create LLAT via WebSocket
LLAT=$(python3 << 'PYEOF'
import asyncio, aiohttp, json
async def create_llat():
async with aiohttp.ClientSession() as session:
async with session.ws_connect("ws://localhost:8123/api/websocket") as ws:
await ws.receive_json()
token = json.load(open("/tmp/ha-tokens.json"))["access_token"]
await ws.send_json({"type": "auth", "access_token": token})
await ws.receive_json()
await ws.send_json({
"id": 1, "type": "auth/long_lived_access_token",
"client_name": "CI Test", "lifespan": 1
})
msg = await ws.receive_json()
print(msg["result"])
asyncio.run(create_llat())
PYEOF
)
# Write MCP config
mkdir -p ~/.config/ha-dev-mcp
cat > ~/.config/ha-dev-mcp/config.json << EOF
{
"homeAssistant": { "url": "$HA_BASE", "token": "$LLAT" },
"safety": {
"allowServiceCalls": true, "requireDryRun": false,
"blockedServices": ["homeassistant.restart","homeassistant.stop"]
},
"features": { "docs": true, "validation": true }
}
EOF
echo "Onboarding complete. HA version:"
curl -sf "$HA_BASE/api/config" -H "Authorization: Bearer $LLAT" | python3 -c "import sys,json; print(json.load(sys.stdin)['version'])"
- name: Configure demo integration
run: |
set -e
HA_BASE="http://localhost:8123"
TOKEN=$(python3 -c "import json,os; c=json.load(open(os.path.expanduser('~/.config/ha-dev-mcp/config.json'))); print(c['homeAssistant']['token'])")
# Initiate demo config flow — capture response body and HTTP status for diagnostics
HTTP_STATUS=$(curl -s -o /tmp/demo_flow.json -w "%{http_code}" \
-X POST "$HA_BASE/api/config/config_entries/flow" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"handler":"demo"}')
echo "Config flow HTTP $HTTP_STATUS:"
cat /tmp/demo_flow.json && echo ""
if [ "$HTTP_STATUS" -lt 200 ] || [ "$HTTP_STATUS" -ge 300 ]; then
echo "ERROR: Failed to initiate demo config flow (HTTP $HTTP_STATUS)"
exit 1
fi
FLOW_ID=$(python3 -c "import json; print(json.load(open('/tmp/demo_flow.json'))['flow_id'])")
echo "Flow ID: $FLOW_ID"
# Complete the flow (demo requires no user input)
HTTP_STATUS2=$(curl -s -o /tmp/demo_result.json -w "%{http_code}" \
-X POST "$HA_BASE/api/config/config_entries/flow/$FLOW_ID" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{}')
echo "Flow completion HTTP $HTTP_STATUS2:"
cat /tmp/demo_result.json && echo ""
python3 -c "import json; r=json.load(open('/tmp/demo_result.json')); print(f'Demo setup result: {r.get(\"type\", \"unknown\")}')"
- name: Build MCP server
run: cd mcp-server && npx tsc
- name: Wait for demo entities
run: sleep 30
- name: Run REST API tests
run: node tests/e2e/test-mcp-rest.mjs
- name: Run WebSocket tests
run: node tests/e2e/test-mcp-websocket.mjs