- _corebuild.musl_platform_tag(): на musl (Alpine/HA OS) bdist_wheel выпускает py3-none-musllinux_X_Y_<arch> вместо linux_<arch> — иначе pip ставит glibc-сборку и dlopen падает на ld-linux-x86-64.so.2 - shared-библиотека линкуется со -static-libstdc++ -static-libgcc (gcc): NEEDED только libm/libc (проверено readelf), меньше зависимостей у HA OS - Gitea Actions: job build-musllinux (container python:3.12-alpine) собирает и публикует musl-wheel; build-glibc — как раньше; общий scripts/publish-gitea-pypi.sh с пропуском уже загруженных файлов - тесты musl_platform_tag; RELEASE_HA §1.1-1.4 (выбор wheel, переустановка на HA OS, ручная сборка musllinux без container:); README troubleshooting
180 lines
9.7 KiB
Markdown
180 lines
9.7 KiB
Markdown
# Релиз и установка HA-интеграции
|
||
|
||
## 1. Внутренняя сборка и установка (Gitea, текущий режим)
|
||
|
||
Внутренний репозиторий — Gitea (`git.ratigorsk-12.ru`), поэтому:
|
||
|
||
* HACS к Gitea **не подключается** (только публичный GitHub) — для
|
||
внутреннего использования интеграция ставится копированием
|
||
`custom_components/fglair/` в `<config>/custom_components/`;
|
||
* зависимость `pyfglair` публикуется в **PyPI-реестр пакетов Gitea** и
|
||
ставится оттуда.
|
||
|
||
### 1.1. Сборка и публикация wheel (Gitea Actions, ручной запуск)
|
||
|
||
Workflow: `.gitea/workflows/publish-pyfglair.yaml` (workflow объявляет
|
||
`permissions: contents: read, packages: write`).
|
||
|
||
Авторизация — любой из вариантов:
|
||
|
||
* **Встроенный job-токен** (Gitea ≥ 1.27, где `packages` поддержан у
|
||
features): ничего настраивать не нужно, workflow возьмёт
|
||
`${{ secrets.GITEA_TOKEN }}`;
|
||
* **Personal access token** со scope `write:package` (для версий, где
|
||
публикация пакетов job-токеном ещё не реализована — см. HACS-док Gitea
|
||
«Package repository authorization»): положите его в секрет
|
||
`PYPI_TOKEN`, при необходимости задайте `PYPI_USER` (имя пользователя к
|
||
PAT; иначе — актор запуска). **Имена секретов не могут начинаться с
|
||
`GITEA_`** — префикс зарезервирован Gitea.
|
||
|
||
Запуск: Actions → **Publish pyfglair** → Run workflow (вход
|
||
`bundled_mbedtls`: `1` — встроить mbedtls, `0` — системный
|
||
`libmbedtls-dev`). Собираются **два** wheel одной версии:
|
||
|
||
* `py3-none-linux_x86_64` — glibc (HA Supervised/Core на Debian/Ubuntu);
|
||
* `py3-none-musllinux_1_2_x86_64` — musl (**HA OS**, Alpine-контейнер);
|
||
job `build-musllinux` выполняется в `container: python:3.12-alpine`
|
||
(нужен `container:` у runner'а; иначе см. §1.4).
|
||
|
||
Артефакты появятся в
|
||
`https://git.ratigorsk-12.ru/api/packages/<owner>/pypi/simple/pyfglair/`
|
||
(`<owner>` — владелец репозитория, напр. `esphome`). C++-рантайм в .so
|
||
встроен (`-static-libstdc++ -static-libgcc`), поэтому wheel зависит только
|
||
от libc/libm соответствующей платформы.
|
||
|
||
Workflow собирает `wheel` + `sdist`, прогоняет smoke-тест установки
|
||
(запускается из `/tmp` с `python -P`, чтобы не подхватить исходники
|
||
`pyfglair/` вместо wheel) и публикует через `twine upload`. Twine 7 не
|
||
поддерживает `--skip-existing` для не-PyPI репозиториев, поэтому workflow
|
||
сам проверяет simple-индекс Gitea и пропускает загрузку, если версия уже
|
||
опубликована. Для новой версии поднимите `version` в `pyproject.toml`.
|
||
|
||
### 1.2. Установка pyfglair в Home Assistant
|
||
|
||
Выбор wheel pip делает сам по платформе: на HA OS (Alpine/musl) — из
|
||
musllinux, на HA Supervised/Core (Debian/glibc) — из linux-сборки.
|
||
|
||
Пакет обязателен (cffi-биндинги). Варианты:
|
||
|
||
* **Вручную в окружение HA** (проще всего для теста; HA увидит
|
||
установленный дистрибутив и не будет вызывать pip для `pyfglair>=1.0.0`):
|
||
|
||
```sh
|
||
# в контейнере/venv Home Assistant (Advanced SSH & Web Terminal, docker exec и т.п.)
|
||
pip install --index-url https://<user>:<token>@git.ratigorsk-12.ru/api/packages/<owner>/pypi/simple \
|
||
--no-deps pyfglair
|
||
```
|
||
|
||
* **Через индекс pip в окружении HA** (`pip.conf`/`PIP_EXTRA_INDEX_URL`):
|
||
тогда HA сам поставит `pyfglair` из манифеста. Учтите риск dependency
|
||
confusion при `--extra-index-url` — для внутреннего стенда допустимо.
|
||
|
||
Если при добавлении интеграции HA пишет «Invalid handler specified» —
|
||
пакет `pyfglair` не установлен (или компонент не перезапущен). Смотрите
|
||
`grep -iE "fglair|pyfglair" /config/home-assistant.log`: при
|
||
`ModuleNotFoundError: No module named 'pyfglair'` установите пакет в
|
||
окружение HA (`docker exec homeassistant python -m pip install ...`) и
|
||
полностью перезапустите HA.
|
||
|
||
* **Публичный PyPI** — см. §2 (для распространения вне сети).
|
||
|
||
### 1.3. Если HA уже установил glibc-wheel на HA OS
|
||
|
||
Симптом: `OSError: cannot load library ... Error loading shared library
|
||
ld-linux-x86-64.so.2: No such file or directory`. Переустановите пакет с
|
||
musllinux-сборкой:
|
||
|
||
```sh
|
||
docker exec homeassistant python -m pip uninstall -y pyfglair
|
||
docker exec homeassistant python -m pip install --no-deps --index-url \
|
||
https://<user>:<token>@git.ratigorsk-12.ru/api/packages/<owner>/pypi/simple \
|
||
pyfglair
|
||
docker exec homeassistant python -c "import pyfglair; print(pyfglair.__version__)"
|
||
docker restart homeassistant
|
||
```
|
||
|
||
### 1.4. Ручная сборка musllinux (если runner без `container:`)
|
||
|
||
```sh
|
||
docker run --rm -v "$PWD":/src -w /src python:3.12-alpine sh -c '
|
||
apk add --no-cache git cmake ninja g++ make curl libstdc++-dev &&
|
||
pip install build &&
|
||
python -m build --wheel'
|
||
# dist/pyfglair-<ver>-py3-none-musllinux_1_2_x86_64.whl
|
||
|
||
pip install twine
|
||
python -m twine upload --repository-url \
|
||
https://git.ratigorsk-12.ru/api/packages/<owner>/pypi \
|
||
-u <user> -p <token> dist/*musllinux*.whl
|
||
```
|
||
|
||
### 1.5. Обновление интеграции
|
||
|
||
`custom_components/fglair/` обновляется из Gitea (git pull / копирование),
|
||
затем перезапуск HA. `pyfglair` — переустановкой из пакетов Gitea.
|
||
|
||
## 2. Публикация pyfglair на PyPI (если понадобится публично)
|
||
|
||
PyPI (warehouse) принимает только `manylinux*`/`musllinux*` теги, поэтому
|
||
локальный `py3-none-linux_x86_64` нужно чинить auditwheel'ом в контейнере
|
||
со старой glibc:
|
||
|
||
```sh
|
||
pip install build auditwheel twine
|
||
|
||
# для каждой архитектуры (linux x86_64/aarch64) в manylinux-контейнере:
|
||
python -m build --wheel
|
||
auditwheel repair dist/pyfglair-*.whl --plat manylinux2014_x86_64 -w dist/manylinux/
|
||
rm -f dist/pyfglair-*-linux_*.whl
|
||
python -m build --sdist
|
||
twine upload dist/manylinux/* dist/*.tar.gz
|
||
```
|
||
|
||
Проверки: `scripts/py-ci.sh`, `scripts/ci.sh`, `readelf -d` по `.so`
|
||
(нет внешней `libmbedcrypto`), установка wheel в чистый venv.
|
||
|
||
## 3. GitHub-зеркало и Custom Repositories (HACS)
|
||
|
||
HACS устанавливает интеграции только с публичных **GitHub**-репозиториев
|
||
(GitLab/Gitea не поддерживаются:
|
||
https://hacs.xyz/docs/faq/other_git_providers/). Публикация в
|
||
default-репозиторий HACS не требуется — достаточно Custom Repositories, но
|
||
хостинг обязан быть GitHub.
|
||
|
||
```sh
|
||
git remote add github git@github.com:<owner>/fgl-aircon.git
|
||
git push --mirror github
|
||
```
|
||
|
||
После зеркала:
|
||
|
||
* заполнить на GitHub Description, Topics (`home-assistant`, `hacs`,
|
||
`fujitsu`, `air-conditioner`), включить Issues (проверяет HACS Action);
|
||
* проверить `codeowners` в manifest (`@petr.polezhaev`; для GitHub нужен
|
||
реальный GitHub-логин);
|
||
* обновить `version` манифеста под тег; заменить заглушки
|
||
`screenshots/step-N.png` и `brand/*.png` реальными ассетами;
|
||
* создать тег (semver) — HACS покажет версию.
|
||
|
||
Готовые файлы HACS: `hacs.json`, `info.md`, `LICENSE` (MIT),
|
||
`custom_components/fglair/brand/` (icon/icon@2x/logo + dark-варианты),
|
||
workflows `.github/workflows/{validate-hacs,hassfest}.yaml`.
|
||
|
||
## 4. Приёмка на живом стенде
|
||
|
||
* `tests/acceptance/test_esphome_ha.py quick` — матрица изменений (HA;
|
||
с `--esphome-host` шаги «режим/уставка» идут через ESPHome, проверка — по
|
||
состоянию в HA), возврат к исходному.
|
||
* `long --hours 24 --interval 3600 --report acceptance.csv`.
|
||
* Сценарии: 503 (два слота), key_error + Repair, offline/восстановление,
|
||
два устройства, options flow (копирование/смена ключа), reconfigure.
|
||
|
||
## 5. Ограничения стенда
|
||
|
||
* Реального железа/облака в CI нет: протокол проверен mock-модулем,
|
||
облако — мок-сервером; приёмочный скрипт имеет self-test на моке HA REST.
|
||
* Суточный soak, re-key и облачный вход — только на приборе/аккаунте.
|
||
* Gitea Actions: встроенный `GITEA_TOKEN` не публикует пакеты (нужен PAT);
|
||
`actions/checkout`/`setup-python` тянутся с github.com (для изолированного
|
||
инстанса используйте абсолютные URL зеркал).
|