ha(ci): Gitea Actions — сборка и публикация pyfglair в PyPI-реестр пакетов Gitea

- .gitea/workflows/publish-pyfglair.yaml: ручной workflow_dispatch —
  toolchain, python -m build (wheel+sdist), smoke-тест wheel, twine upload
  в /api/packages/<owner>/pypi (PAT в секрете GITEA_PYPI_TOKEN; встроенный
  GITEA_TOKEN пакеты публиковать не умеет); вход bundled_mbedtls
- setup.py: FGL_BUNDLED_MBEDTLS=0 уважается при сборке wheel (системный
  mbedtls), по умолчанию — встроенный (проверено readelf для обоих)
- RELEASE_HA переписан: §1 внутренняя установка (Gitea Packages + команда
  pip install для HA), §2 PyPI (публично), §3 GitHub/HACS (Custom
  Repositories только на GitHub), §4-5 без изменений
- README компонента: внутренняя установка pyfglair из Gitea Packages
This commit is contained in:
2026-09-29 15:44:56 +03:00
parent 34cdb7fef8
commit a32e2f0bfc
4 changed files with 194 additions and 74 deletions
+91 -70
View File
@@ -1,99 +1,120 @@
# Чек-лист релиза HA-интеграции (H5)
# Релиз и установка HA-интеграции
## 1. Публикация pyfglair (PyPI)
## 1. Внутренняя сборка и установка (Gitea, текущий режим)
Манифест компонента требует `pyfglair>=1.0.0`; штатный installer HA
резолвит требования только через PyPI. PyPI (warehouse) принимает только
`manylinux*`/`musllinux*` платформенные теги — локальный
`py3-none-linux_x86_64` будет отклонён (`HTTP 400 unsupported platform
tag`), поэтому wheel нужно «починить» auditwheel'ом в контейнере со старой
glibc (manylinux):
Внутренний репозиторий — 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`.
1. Создайте personal access token Gitea со scope `write:package`
(Settings → Applications → Generate token).
2. Settings репозитория → Actions → Secrets:
* `GITEA_PYPI_TOKEN` — этот токен (обязательно);
* `GITEA_PYPI_USER` — имя пользователя Gitea (опционально; иначе актор
запуска).
3. Actions → **Publish pyfglair** → Run workflow (вход `bundled_mbedtls`:
`1` — встроить mbedtls, `0` — системный `libmbedtls-dev`).
4. Артефакт появится в: `https://git.ratigorsk-12.ru/api/packages/<owner>/pypi/simple/pyfglair/`
(`<owner>` — владелец репозитория, напр. `esphome`).
Workflow собирает `wheel` + `sdist`, прогоняет smoke-тест установки и
публикует через `twine upload --skip-existing`. Повторная публикация той же
версии пропускается; для новой версии поднимите `version` в
`pyproject.toml`.
### 1.2. Установка pyfglair в Home Assistant
Пакет обязателен (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` — для внутреннего стенда допустимо.
* **Публичный PyPI** — см. §2 (для распространения вне сети).
### 1.3. Обновление интеграции
`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-контейнере
# (например, quay.io/pypa/manylinux2014_<arch>):
python -m build --wheel # .so без внешнего mbedcrypto
auditwheel repair dist/pyfglair-*.whl \
--plat manylinux2014_x86_64 -w dist/manylinux/ # или manylinux_2_28
rm -f dist/pyfglair-*-linux_*.whl # linux-тег PyPI отклонит
python -m build --sdist # sdist с C++-исходниками (MANIFEST.in)
# для каждой архитектуры (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.
* `scripts/py-ci.sh` — pyfglair + acceptance self-test + components;
* `scripts/ci.sh` — ядро (gcc/clang, ASan/UBSan) 11/11;
* `readelf -d build-pyfglair/libfgl-aircon.so*` (или распакованный wheel:
`pyfglair/libfgl-aircon.so*`) — нет внешней `libmbedcrypto` (встроен);
* `auditwheel show` для repaired-wheel — тег manylinux и только
базовые системные библиотеки;
* установка wheel в чистый venv вне репозитория:
`python -c "import pyfglair.session"`;
* aarch64: сборка в соответствующем manylinux-контейнере (QEMU или
нативная), иначе пользователи ARM не смогут поставить `pyfglair`.
Альтернатива — cibuildwheel (`pip install cibuildwheel`) с `auditwheel
repair` внутри, но текущий `bdist_wheel`-хук отдаёт тег
`py3-none-<plat>`, поэтому проверяйте итоговые теги вручную.
## 2. GitHub-зеркало и Custom Repositories
## 3. GitHub-зеркало и Custom Repositories (HACS)
HACS устанавливает интеграции только с публичных **GitHub**-репозиториев
(GitLab/Gitea не поддерживаются: https://hacs.xyz/docs/faq/other_git_providers/).
Публикация в default-репозиторий HACS не требуется — достаточно Custom
Repositories, но хостинг обязан быть 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` в `custom_components/fglair/manifest.json` —
сейчас `@petr.polezhaev`; для GitHub Action/HACS это должен быть реальный
GitHub-логин;
* проверить `documentation`/`issue_tracker` в манифесте;
* обновить `version` манифеста под номер тега (сейчас `0.1.0`, pyfglair —
`1.0.0`; компонент и пакет версионируются отдельно);
* заменить заглушки `custom_components/fglair/screenshots/step-N.png`
реальными скриншотами (описания «что должно быть видно» — в README);
* заменить заглушки `custom_components/fglair/brand/*.png` фирменными
ассетами (сейчас — сгенерированные плейсхолдеры: icon/icon@2x/logo и
тёмные варианты);
* создать git-тег (semver) в GitHub-зеркале — HACS покажет версию.
* заполнить на 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/hassfest проверяют у интеграции: `hacs.json`,
`custom_components/fglair/manifest.json` (domain/documentation/
issue_tracker/codeowners/name/version), `custom_components/fglair/brand/icon.png`,
README/info.md, OSI-лицензия (`LICENSE`, MIT). Всё это в репозитории есть;
workflow `.github/workflows/{validate-hacs,hassfest}.yaml` включатся на
GitHub.
Готовые файлы HACS: `hacs.json`, `info.md`, `LICENSE` (MIT),
`custom_components/fglair/brand/` (icon/icon@2x/logo + dark-варианты),
workflows `.github/workflows/{validate-hacs,hassfest}.yaml`.
## 3. Приёмка на живом стенде
## 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 без потери конверсий.
* `long --hours 24 --interval 3600 --report acceptance.csv`.
* Сценарии: 503 (два слота), key_error + Repair, offline/восстановление,
два устройства, options flow (копирование/смена ключа), reconfigure.
## 4. Ограничения текущего стенда
## 5. Ограничения стенда
* Реального железа/облака в CI нет: протокол проверен mock-модулем
(`tests/ayla/mock_ac.py`), облако — мок-сервером; приёмочный скрипт имеет
self-test на моке HA REST.
* Реального железа/облака в CI нет: протокол проверен mock-модулем,
облако — мок-сервером; приёмочный скрипт имеет self-test на моке HA REST.
* Суточный soak, re-key и облачный вход — только на приборе/аккаунте.
* ESPHome-канал приёмки требует установленного `aioesphomeapi` и
работающего ESPHome-компонента (PLAN_ESPHOME); без них скрипт работает
только со стороны HA.
* Gitea Actions: встроенный `GITEA_TOKEN` не публикует пакеты (нужен PAT);
`actions/checkout`/`setup-python` тянутся с github.com (для изолированного
инстанса используйте абсолютные URL зеркал).