Skip to content

Latest commit

 

History

History
161 lines (132 loc) · 7.19 KB

CONTRIBUTING.md

File metadata and controls

161 lines (132 loc) · 7.19 KB

Contributing to HA Dev Tools

Thanks for your interest in contributing. This document covers how the project is actually built and tested today - see docs/ARCHITECTURE.md for why it's built this way.

Code of Conduct

This project follows the Home Assistant Code of Conduct.

Project structure

ha-dev-tools/
├── custom_components/ha_dev_tools/
│   ├── __init__.py            # Integration setup
│   ├── manifest.json
│   ├── config_flow.py
│   ├── const.py
│   ├── llm_api.py             # Tool definitions, registered into HA's llm.API registry
│   ├── access_control.py      # The arm-file + admin gate every tool goes through
│   ├── security.py            # Path allowlist/denylist for file-touching tools
│   ├── file_manager.py / log_manager.py / automation_manager.py /
│   │   entity_manager.py / helper_manager.py / dashboard_manager.py /
│   │   template_manager.py / supervisor_manager.py / audit_manager.py /
│   │   config_tools.py        # Backing logic each Tool calls into
│   └── ws_call.py             # In-process WebSocket API loopback (helpers, dashboards)
├── tests/                     # Flat pytest files, one per module above
│   └── property/              # Hypothesis property-based tests
├── docs/                      # ARCHITECTURE.md, SECURITY.md
├── .github/workflows/         # test.yml, test-latest-ha.yml, hassfest.yml, validate.yml
├── requirements-test.txt      # current HA release (default)
├── requirements-test-ha-min.txt  # minimum HA from hacs.json
├── requirements-test-mariadb.txt # + MariaDB driver, for the statistics tests
└── requirements-test-common.txt  # shared by both

Prerequisites

  • Python 3.14+. requirements-test.txt pins homeassistant transitively to a version whose own Requires-Python floor is 3.14.2 - anything older can't install it at all. test.yml's CI matrix runs Python 3.14 exclusively for the same reason.
  • Git.

Development setup

git clone https://github.com/YOUR_USERNAME/ha-dev-tools.git
cd ha-dev-tools
python3.14 -m venv .venv
source .venv/bin/activate
pip install -r requirements-test.txt

requirements-test.txt pins pytest-homeassistant-custom-component to an exact version, which transitively pins an exact homeassistant version too

  • this isn't a loose floor, it's deliberately reproducible. It targets the current HA release. CI also runs the suite against the minimum HA version in hacs.json (requirements-test-ha-min.txt), and a nightly workflow (test-latest-ha.yml) runs it against the newest HA release, so a breaking HA change shows up before users hit it (issue #84).

When the nightly run goes red (a new HA release): bump pytest-homeassistant-custom-component in requirements-test.txt, then re-verify the conversation pins (gazetteer-matcher, hassil, home-assistant-intents) against homeassistant/components/conversation/ manifest.json in the newly installed HA - the nightly job prints the component requirements it read. When raising the minimum HA version, update hacs.json and requirements-test-ha-min.txt together. See the comments in the requirements files for why each pin exists, and docs/ARCHITECTURE.md for what broke the last time a pin was assumed rather than checked.

To test against the minimum HA locally, use a separate venv with pip install -r requirements-test-ha-min.txt.

Statistics writes on MariaDB (issue #148): only there do HA's statistics import and sum adjustment retry a lock-wait timeout or a deadlock, so CI's test (MariaDB) job runs tests/test_statistics_*.py against a MariaDB 10.11 recorder, and tests/test_statistics_mysql.py (skipped on SQLite) adds real row locks. Locally, with a MariaDB server and libmariadb-dev:

pip install -r requirements-test-mariadb.txt
PYTHONPATH=. pytest tests/test_statistics_*.py \
  --dburl "mysql://USER:PASSWORD@127.0.0.1:3306/ha_test?charset=utf8mb4" \
  --drop-existing-db

The user needs to create and drop databases and to SET GLOBAL innodb_lock_wait_timeout (the lock tests shorten it to 1 s and restore it).

A note on local verification: if your local Python isn't genuinely 3.14.2+, you may not be able to install the real dependency graph at all

  • pip will silently resolve to whichever older homeassistant release your interpreter can satisfy instead of erroring, which looks identical to "nothing changed" until you check what actually got installed (pip show homeassistant). When in doubt, trust CI's output over a local run of unknown provenance.

Running tests

PYTHONPATH=. pytest tests/ --ignore=tests/property/ -v
PYTHONPATH=. pytest tests/property/ -v --hypothesis-show-statistics

There's no tests/unit//tests/integration/ split - tests live flat in tests/, one file per module, using real pytest-homeassistant-custom-component fixtures (a real hass instance, not a mock) rather than hand-rolled mocks. Prefer that pattern for new tests: exercise the real Home Assistant machinery (real WS command dispatch, real config entry setup) wherever practical, and reserve mocks for things that genuinely can't run in a sandbox (Supervisor, an actual MCP client).

A recurring gotcha: the default hass fixture reuses one physical testing_config directory across test runs rather than a fresh per-test tmp dir. Any test that writes a real file into hass.config.config_dir needs its own cleanup (see test_access_control.py's _clean_arm_file fixture for the pattern) or it will leak state into whatever test runs next.

Code style

  • 4-space indentation, type hints on function signatures, docstrings on public functions/classes.
  • No comments explaining what code does - name things so it's obvious. Comments here explain why, especially where behavior was verified against actual Home Assistant source rather than assumed - see any existing module's docstring for the house style.

Submitting changes

  1. Branch off main with a descriptive name (feature/..., fix/...).
  2. Add tests for new functionality; don't reduce coverage.
  3. Run the full local suite, and if you touched anything version-sensitive (HA API surface, Python version handling), verify against a genuinely fresh install rather than your accumulated local venv - see the note above.
  4. Add a CHANGELOG.md entry under [Unreleased].
  5. Open a PR describing what changed and why.

Reporting issues

Bug reports should include: what you expected vs. what happened, reproduction steps, your Home Assistant and this integration's versions, and relevant log entries (custom_components.ha_dev_tools: debug under logger.logs in configuration.yaml gets you more detail).

Security issues: please don't open a public issue. See docs/SECURITY.md for the threat model this project defends against, then report privately via a GitHub security advisory or to the maintainer directly.

License

By contributing, you agree your contributions are licensed under this project's MIT License.