feat: persistent settings UI for stdio mode #3306
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
| name: PR Validation Pipeline | |
| permissions: | |
| contents: read | |
| on: | |
| pull_request: | |
| branches: [ master ] | |
| workflow_dispatch: | |
| 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.5.3" | |
| # 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: | |
| lockfile: | |
| name: Check uv.lock | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.15-python3.13-trixie-slim | |
| timeout-minutes: 2 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Verify uv.lock is in sync with pyproject.toml | |
| run: uv lock --check | |
| lint: | |
| name: Ruff Lint | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.15-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Install git for changed-files diff | |
| run: apt-get update -qq && apt-get install -y -qq git >/dev/null 2>&1 | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run ruff check | |
| run: uv run ruff check src/ tests/ homeassistant-addon/ homeassistant-addon-webhook-proxy/ scripts/ | |
| - name: Run ruff format check on changed Python files | |
| run: | | |
| # actions/checkout@v6 sets safe.directory in a temp HOME that this | |
| # step doesn't inherit; re-add it here so git operations succeed | |
| # when the checkout dir is owned by a different UID than the | |
| # container's root. | |
| git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| # Changed-files-only gate per the maintainer call on issue #1318: | |
| # new edits must be formatted; pre-existing format-debt on | |
| # untouched files stays grandfathered. Avoids the disruption of a | |
| # repo-wide sweep while still preventing fresh debt from landing. | |
| if [ -z "${GITHUB_BASE_REF}" ]; then | |
| echo "No PR base ref (workflow_dispatch); skipping format check." | |
| exit 0 | |
| fi | |
| git fetch --depth=1 origin "${GITHUB_BASE_REF}" | |
| base_sha=$(git rev-parse "origin/${GITHUB_BASE_REF}") | |
| changed_py=$(git diff --name-only --diff-filter=ACMR "${base_sha}" -- '*.py') | |
| if [ -z "$changed_py" ]; then | |
| echo "No Python files changed; skipping ruff format check." | |
| exit 0 | |
| fi | |
| count=$(echo "$changed_py" | wc -l) | |
| echo "Checking ruff format on $count changed Python files:" | |
| echo "$changed_py" | sed 's/^/ /' | |
| echo "$changed_py" | xargs uv run ruff format --check | |
| ast-grep: | |
| name: AST Lint | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.15-python3.13-trixie-slim | |
| timeout-minutes: 2 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run ast-grep | |
| run: uv run ast-grep scan | |
| mypy: | |
| name: Mypy Type Check | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.15-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Run mypy | |
| run: | | |
| uv run mypy src/ homeassistant-addon/ scripts/ | |
| uv run mypy homeassistant-addon-webhook-proxy/start.py | |
| # Fast unit tests (no Docker, no HA instance needed) | |
| unit-tests: | |
| name: Unit Tests | |
| runs-on: ubuntu-latest | |
| container: | |
| # renovate: datasource=docker depName=ghcr.io/astral-sh/uv | |
| image: ghcr.io/astral-sh/uv:0.11.15-python3.13-trixie-slim | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Install git for submodule checkout | |
| run: apt-get update -qq && apt-get install -y -qq git >/dev/null 2>&1 | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Install dependencies | |
| run: uv sync --all-extras --dev | |
| - name: Run unit tests | |
| run: uv run pytest tests/src/unit/ -n auto --tb=short -v | |
| # Comprehensive E2E validation for all PRs | |
| e2e-validation: | |
| name: E2E Validation (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| timeout-minutes: 15 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: | |
| - ubuntu-latest # Linux x64 | |
| - ubuntu-24.04-arm # Linux ARM64 | |
| include: | |
| - os: ubuntu-latest | |
| pytest_workers: 3 | |
| - os: ubuntu-24.04-arm | |
| pytest_workers: 4 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| cache-binary: true | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| 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@v5 | |
| 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 ${{ matrix.pytest_workers }} workers..." | |
| uv run pytest tests/src/e2e/ \ | |
| -n${{ matrix.pytest_workers }} \ | |
| --dist loadscope \ | |
| --tb=short \ | |
| -v | |
| echo "✅ Full E2E test suite passed" | |
| env: | |
| HAMCP_ENV_FILE: "tests/.env.test" | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Docker and Add-on validation | |
| docker-validation: | |
| name: Docker & Add-on Validation | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| with: | |
| cache-binary: true | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: "latest" | |
| - name: Set up Python | |
| run: uv python install ${{ env.PYTHON_VERSION }} | |
| - name: Install test dependencies | |
| run: uv sync --dev | |
| - name: Run add-on tests | |
| run: uv run pytest tests/addon/ --ignore=tests/addon/test_skills_config.py --tb=short -v | |
| - name: Validate docker-compose configuration | |
| run: uv run pytest tests/test_docker/test_docker_compose.py -v | |
| - name: Build and test standalone Docker image | |
| run: uv run pytest tests/test_docker/test_docker_build.py -v |