Files
MeshCore/ci/README.md
T

11 KiB
Raw Blame History

CI: автоматическая сборка прошивок на своём Gitea

Схема: Gitea (systemd) → Gitea Runner на том же сервере → PlatformIO → артефакты out/. Сборка идёт через build.sh из репозитория, то есть тем же путём, что и локально (версия прошивки, merge-bin для ESP32, .uf2 для nRF52), — логика не дублируется.

Что где лежит

Файл Назначение
.gitea/workflows/firmware.yml workflow: клон, кэш, сборка, артефакты (запуск только вручную)
ci/build-firmwares.sh сборка выбранного набора env (годится и для запуска руками)
ci/build-local.ps1 сборка на своей машине под Windows и публикация релиза в Gitea
ci/act_runner/gitea-runner.service systemd-юнит раннера
ci/act_runner/config.yaml конфиг раннера: ёмкость, таймаут, кэш
ci/act_runner/docker-compose.yml альтернатива: раннер в Docker

1. Что должно быть на сервере

apt-get update
apt-get install -y git python3 python3-venv python3-pip curl ca-certificates build-essential
  • python3-pip обязателен: без него python3 -m venv создаёт окружение без pip, и шаг установки PlatformIO падает. Готовое окружение workflow пересоздаст сам.
  • Свободного места нужно 5 ГБ: тулчейны PlatformIO занимают ~800 МБ на одну платформу, а при сборке и ESP32, и nRF52 — заметно больше.
  • Swap желателен. На VPS с 2 ГБ RAM линковка ESP32 упирается в память:
    fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
    echo '/swapfile none swap sw 0 0' >> /etc/fstab
    

2. Включение Actions в Gitea

В /etc/gitea/app.ini (владелец git:git, права 600):

[actions]
ENABLED = true
# значение — github или gitea (ссылка не поддерживается)
DEFAULT_ACTIONS_URL = github
# workflow ищем только здесь, чтобы не подхватывались upstream-файлы
WORKFLOW_DIRS = .gitea/workflows

После правки: systemctl restart gitea. Перед изменением делайте копию конфига — cp -a /etc/gitea/app.ini /etc/gitea/app.ini.bak.

3. Установка раннера (systemd)

useradd --create-home --home-dir /var/lib/act-runner --shell /bin/bash act-runner

# актуальный релиз: https://gitea.com/gitea/runner/releases
curl -fsSL -o /usr/local/bin/gitea-runner \
  https://gitea.com/gitea/runner/releases/download/v5.0.0/gitea-runner-5.0.0-linux-amd64
chmod +x /usr/local/bin/gitea-runner
gitea-runner --version

install -d -o act-runner -g act-runner /var/lib/act-runner
cp ci/act_runner/config.yaml /var/lib/act-runner/config.yaml
chown act-runner:act-runner /var/lib/act-runner/config.yaml

Токен — обязательно со scope репозитория: без --scope раннер становится глобальным и начинает брать задачи всех репозиториев инстанса:

# от имени пользователя Gitea (CLI не работает под root)
su - git -c "gitea actions generate-runner-token -c /etc/gitea/app.ini --scope shade/MeshCore" \
  > /var/lib/act-runner/reg-token
chown act-runner:act-runner /var/lib/act-runner/reg-token && chmod 600 /var/lib/act-runner/reg-token

su - act-runner -c "/usr/local/bin/gitea-runner register --no-interactive \
  --instance https://git.meshinfo.ru \
  --token-file /var/lib/act-runner/reg-token \
  --name meshcore-builder \
  --labels ubuntu-latest:host \
  -c /var/lib/act-runner/config.yaml"

rm -f /var/lib/act-runner/reg-token     # токен больше не нужен

Метка ubuntu-latest:host означает, что шаги выполняются прямо на сервере — без Docker, но зависимости ставятся в систему. Метка должна совпадать с runs-on в workflow.

cp ci/act_runner/gitea-runner.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now gitea-runner
systemctl status gitea-runner
journalctl -u gitea-runner -f      # ждём "declare successfully"

Альтернатива: раннер в Docker

cd ci/act_runner && cp .env.example .env && nano .env && docker compose up -d

4. Запуск сборки

Workflow запускается только вручную — автоматических сборок по push и тегам нет (прошивки собираются локально и публикуются релизом, см. следующий раздел).

  • Вручную в Gitea — Actions → Firmware build → Run workflow (targets, match, version), либо через API:
    curl -X POST -H "Authorization: token $GITEA_TOKEN" -H 'Content-Type: application/json' \
      -d '{"ref":"main","inputs":{"targets":"Heltec_t096_companion_radio_ble","version":"ci"}}' \
      https://git.meshinfo.ru/api/v1/repos/shade/MeshCore/actions/workflows/firmware.yml/dispatches
    
  • Локально — тем же скриптом, что запускает CI:
    FIRMWARE_VERSION=v1.0.0 bash ci/build-firmwares.sh
    MATCH=promicro bash ci/build-firmwares.sh
    TARGETS="Heltec_t096_companion_radio_ble" bash ci/build-firmwares.sh
    

Готовые файлы попадают в out/ (каталог в .gitignore); при запуске в Gitea они выгружаются артефактом firmware.

Локально на Windows, без нагрузки на сервер

На этом VPS всего 1 CPU, поэтому полный набор прошивок собирается там часами. Разумнее собрать у себя, а на сервер отправить только готовые файлы — релизом Gitea:

# быстрый набор: все env, в имени которых есть подстрока
.\ci\build-local.ps1 -Match promicro -Version v1.0.0

# полный набор из DEFAULT_TARGETS
.\ci\build-local.ps1 -Version v1.0.0

# собрать и опубликовать релиз
$env:GITEA_TOKEN = '<токен с правом write:repository>'
.\ci\build-local.ps1 -Version v1.0.0 -Publish -Public -Tag v1.0.0

# опубликовать уже собранное, без пересборки
.\ci\build-local.ps1 -Version v1.0.0 -SkipBuild -Publish -Public -Tag v1.0.0

Скрипт находит Git Bash и PlatformIO, подставляет рабочий python3, чистит out/ перед сборкой, а с -Publish создаёт тег и релиз, прикрепляя к нему файлы (-Public публикует сразу, без флага создаётся черновик). Токен нужен только для публикации: сама сборка работает без него.

На Linux/macOS то же самое делается напрямую: FIRMWARE_VERSION=v1.0.0 bash ci/build-firmwares.sh.

5. Релизы

Релиз собирается и публикуется локально: ci/build-local.ps1 -Publish -Public -Tag <тег> (см. выше). Скрипт создаёт тег на текущем коммите, релиз в Gitea и прикрепляет к нему .bin / .uf2 / .zip; версия -Version попадает в имена файлов (<env>-v1.0.0-<sha>.uf2). Если тег уже существует, он переиспользуется.

В CI шага публикации нет: сервер только собирает прошивки по ручному запуску и отдаёт их артефактом.

Прошивальщик на сайте

Страница https://meshinfo.ru/flasher/ берёт список прошивок из своего index.json (статика в /var/www/flasher, а сами файлы браузер тянет через nginx напрямую из релизов Gitea). Имена файлов в манифесте разобраны на плату, роль, чип и формат, поэтому после каждой публикации релиза его нужно пересобрать — иначе на странице останутся старые ссылки.

.\ci\update-flasher.ps1              # пересобрать и выложить на сервер
.\ci\update-flasher.ps1 -SkipUpload  # только пересобрать, без заливки

Скрипт запускает генератор build-flasher-index.py из соседнего репозитория (..\MeshCore-posadmesh-meshcoretel\posadmesh-tools\; путь задаётся через -Generator или FLASHER_GENERATOR), делает на сервере бэкап старого манифеста, заливает новый и проверяет, что страница отдаёт его, а файлы доступны через /flasher/fw/....

При публикации релиза (ci/build-local.ps1 -Publish) обновление выполняется автоматически, отключить можно флагом -SkipFlasher.

6. Набор прошивок по умолчанию

ci/build-firmwares.sh, массив DEFAULT_TARGETS — 26 env:

  • companion (15): T096, ProMicro (SSD1306 и SH1106), Heltec v3, heltec_v4, heltec_v4 TFT, tracker_v2, T-Deck, T-Echo Card, T114, T190, M9, Meshadventurer (sx1262, sx1262 + e22p 868M30S, e22p 433M30S);
  • repeater (8): Heltec v3, heltec_v4, heltec_v4 TFT, T096, ProMicro, Meshadventurer (sx1262, sx1262 + e22p 868M30S, sx1262 + e22p 433M30S);
  • room server / sensor (3): T096 room server, T096 sensor, ProMicro room server.

7. Время и ресурсы

  • Сервер с 1 CPU / 2 ГБ RAM полный набор собирает часами, поэтому рабочий вариант — собирать полный набор локально (ci/build-local.ps1), а в Gitea запускать вручную только те env, которые нужно проверить.
  • Первая сборка качает тулчейны (nRF52: framework + CMSIS + gcc-arm ≈ 660 МБ; ESP32 — ещё столько же), дальше работает кэш ~/.platformio.
  • capacity: 1 в config.yaml — одна сборка за раз.