Skip to content

chore(internal): machine-translate locale updates #937

chore(internal): machine-translate locale updates

chore(internal): machine-translate locale updates #937

Workflow file for this run

name: E2E Tests
on:
push:
branches: [ main, master ]
paths:
# Only run on code changes, not documentation
- 'src/**'
- 'tests/**'
- 'pyproject.toml'
- 'Dockerfile'
- 'homeassistant-addon/**'
- '.github/workflows/e2e-tests.yml'
workflow_dispatch:
# Limit GITHUB_TOKEN permissions to minimum required
permissions:
contents: read
env:
PYTHON_VERSION: "3.13"
UV_CACHE_DIR: /tmp/.uv-cache
# renovate: datasource=docker depName=ghcr.io/home-assistant/home-assistant
HA_IMAGE_GHCR: "ghcr.io/home-assistant/home-assistant:2026.8.0"
# Disable Testcontainers' Ryuk reaper: it has been reported to leave
# zombie containers on GHA runners (see #366, Ilya0527 2026-05-18).
# The E2E fixture in tests/src/e2e/conftest.py relies instead on the
# enclosing ``with container:`` context manager — Python guarantees
# its ``__exit__`` fires on both normal and exception flows, so the
# Ryuk safety net is not needed for deterministic cleanup. Refs #366.
TESTCONTAINERS_RYUK_DISABLED: "true"
jobs:
# Comprehensive E2E validation for main branch
e2e-tests:
name: E2E Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
with:
cache-binary: true
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Cache HA Docker image
id: cache-ha-image
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: /tmp/ha-image.tar
key: ha-image-${{ env.HA_IMAGE_GHCR }}-${{ runner.arch }}
- name: Load cached HA image
if: steps.cache-ha-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/ha-image.tar
- name: Pull HA image (GHCR → Docker Hub fallback)
if: steps.cache-ha-image.outputs.cache-hit != 'true'
run: |
HA_VERSION="${HA_IMAGE_GHCR##*:}"
HA_IMAGE_DOCKERHUB="homeassistant/home-assistant:${HA_VERSION}"
for registry in "$HA_IMAGE_GHCR" "$HA_IMAGE_DOCKERHUB"; do
echo "Trying $registry..."
if docker pull "$registry"; then
if [ "$registry" != "$HA_IMAGE_GHCR" ]; then
docker tag "$registry" "$HA_IMAGE_GHCR"
fi
docker save "$HA_IMAGE_GHCR" -o /tmp/ha-image.tar
echo "Pulled and cached from $registry"
exit 0
fi
echo "Failed to pull from $registry, trying next..."
sleep 15
done
echo "All registries failed" && exit 1
- name: Run full E2E test suite
run: |
echo "🚀 Running full E2E test suite with 3 workers..."
uv run pytest tests/src/e2e/ \
-n3 \
--dist loadscope \
--tb=short \
-v
echo "✅ Full E2E test suite passed"
env:
HAMCP_ENV_FILE: "tests/.env.test"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# In-process MCP server backend (#1527): the SAME full E2E suite, but the
# server-under-test is the in-process MCP server (ha_mcp_tools entry) running inside
# each worker's testcontainer (E2E_BACKEND=embedded), driven over its ingress
# webhook. Runs in parallel with the container lane above (a separate job — it
# does not extend that job's runtime). Matrixed x64 + arm64 to mirror the PR
# lane (pr.yml's e2e-validation-embedded). -n2/-n3 (vs the container lane's -n3):
# each worker additionally builds a ha-mcp wheel and its container preinstalls
# the fastmcp dependency tree before HA boots, so a lower worker count keeps peak
# memory + concurrent-pip pressure in check (arm gets +1). The larger timeout
# covers that per-worker preinstall window.
e2e-tests-embedded:
name: E2E Tests (Embedded Server, ${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
os:
- ubuntu-latest # Linux x64
- ubuntu-24.04-arm # Linux ARM64
include:
- os: ubuntu-latest
pytest_workers: 2
- os: ubuntu-24.04-arm
pytest_workers: 3
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
submodules: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
with:
cache-binary: true
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Cache HA Docker image
id: cache-ha-image
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: /tmp/ha-image.tar
key: ha-image-${{ env.HA_IMAGE_GHCR }}-${{ runner.arch }}
- name: Load cached HA image
if: steps.cache-ha-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/ha-image.tar
- name: Pull HA image (GHCR → Docker Hub fallback)
if: steps.cache-ha-image.outputs.cache-hit != 'true'
run: |
HA_VERSION="${HA_IMAGE_GHCR##*:}"
HA_IMAGE_DOCKERHUB="homeassistant/home-assistant:${HA_VERSION}"
for registry in "$HA_IMAGE_GHCR" "$HA_IMAGE_DOCKERHUB"; do
echo "Trying $registry..."
if docker pull "$registry"; then
if [ "$registry" != "$HA_IMAGE_GHCR" ]; then
docker tag "$registry" "$HA_IMAGE_GHCR"
fi
docker save "$HA_IMAGE_GHCR" -o /tmp/ha-image.tar
echo "Pulled and cached from $registry"
exit 0
fi
echo "Failed to pull from $registry, trying next..."
sleep 15
done
echo "All registries failed" && exit 1
- name: Run full E2E test suite (embedded backend)
run: |
echo "🚀 Running full E2E suite through the in-process MCP server (embedded backend) with ${{ matrix.pytest_workers }} workers..."
uv run pytest tests/src/e2e/ \
-n${{ matrix.pytest_workers }} \
--dist loadscope \
--tb=short \
-v
echo "✅ Full E2E test suite (embedded backend) passed"
env:
E2E_BACKEND: "embedded"
HAMCP_ENV_FILE: "tests/.env.test"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Update-path e2e lane (#1783/#1785): mirrors pr.yml's e2e-validation-update-path
# on master push. Each run parametrizes over the component source — the released
# ``stable`` git tag (proves a new server release won't break existing installs)
# AND this checkout's working tree (proves the PR's own update machinery still
# works) — with the ha-mcp server installed from PyPI stable in both. The test
# then drives the in-process update that installs THIS commit's freshly built
# wheel over the running server (the real reload/purge/restart path) and asserts
# the server survives. A single ubuntu-latest lane runs both scenarios serially
# (no -n), not the parallel suite. fetch-depth 0 is REQUIRED — the default
# shallow checkout omits the ``stable`` tag the stable scenario checks out from.
e2e-tests-update-path:
name: E2E Tests (Update Path)
runs-on: ubuntu-latest
# 30m: each of the two scenarios (component@stable and component@working-tree)
# does a first bring-up that installs ha-mcp plus the full fastmcp dependency
# tree from PyPI stable before the in-process update swaps in the PR wheel. The
# two containers run sequentially in this one job (observed ~50s per scenario),
# so 30m still fits comfortably.
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
submodules: true
# fetch-depth 0: the update-path scenario checks the custom component
# out at the released ``stable`` git tag, which the default shallow
# checkout does not fetch.
fetch-depth: 0
- name: Verify stable tag is present
run: |
if ! git rev-parse --verify refs/tags/stable >/dev/null 2>&1; then
echo "::error::The 'stable' git tag is missing — the update-path lane checks the released component out from it. Ensure checkout uses fetch-depth: 0."
exit 1
fi
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
with:
cache-binary: true
- name: Install uv
uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
with:
version: "latest"
- name: Set up Python
run: uv python install ${{ env.PYTHON_VERSION }}
- name: Install dependencies
run: uv sync --all-extras --dev
- name: Cache HA Docker image
id: cache-ha-image
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6
with:
path: /tmp/ha-image.tar
key: ha-image-${{ env.HA_IMAGE_GHCR }}-${{ runner.arch }}
- name: Load cached HA image
if: steps.cache-ha-image.outputs.cache-hit == 'true'
run: docker load -i /tmp/ha-image.tar
- name: Pull HA image (GHCR → Docker Hub fallback)
if: steps.cache-ha-image.outputs.cache-hit != 'true'
run: |
HA_VERSION="${HA_IMAGE_GHCR##*:}"
HA_IMAGE_DOCKERHUB="homeassistant/home-assistant:${HA_VERSION}"
for registry in "$HA_IMAGE_GHCR" "$HA_IMAGE_DOCKERHUB"; do
echo "Trying $registry..."
if docker pull "$registry"; then
if [ "$registry" != "$HA_IMAGE_GHCR" ]; then
docker tag "$registry" "$HA_IMAGE_GHCR"
fi
docker save "$HA_IMAGE_GHCR" -o /tmp/ha-image.tar
echo "Pulled and cached from $registry"
exit 0
fi
echo "Failed to pull from $registry, trying next..."
sleep 15
done
echo "All registries failed" && exit 1
- name: Run update-path e2e test
# E2E_BACKEND deliberately UNSET (container backend): the test drives its
# own dedicated container end to end and never touches the session
# backend, but conftest's autouse session fixture boots one regardless —
# the default container backend boots it cheaply, while
# E2E_BACKEND=embedded would add a wheel build + in-container preinstall
# of the whole fastmcp tree that nothing in this lane uses.
run: |
echo "🚀 Running the update-path e2e lane (released component + PyPI server → PR wheel)..."
uv run pytest tests/src/e2e/workflows/embedded/test_embedded_update_path.py \
-m update_path \
--tb=short \
-v
echo "✅ Update-path e2e lane passed"
env:
E2E_UPDATE_PATH: "1"
HAMCP_ENV_FILE: "tests/.env.test"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}