Files
MeshCore/ci/README.md
T

12 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/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 (в bin/ только симлинки python), и шаг установки PlatformIO падает с No such file or directory. Если venv уже создан без pip, 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
# Gitea 1.27 принимает значение github или gitea, но НЕ ссылку:
# "https://github.com" даёт ошибку DEFAULT_ACTIONS_URL does not support ...
DEFAULT_ACTIONS_URL = github
# Искать workflow только в .gitea/workflows: иначе Gitea подхватит upstream-файлы
# из .github/workflows, а у них триггер push — на каждый push запустится сборка
# сотен env и деплой Pages.
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
# (проект переименован: раньше act_runner, теперь Gitea Runner; на момент настройки — v5.0.0)
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 раннер становится глобальным и начинает брать задачи всех репозиториев инстанса (в том числе чужие stale-bot):

# от имени пользователя 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

В свежих версиях образ называется gitea/runner (раньше gitea/act_runner).

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

  • Автоматически — push в main (кроме изменений в *.md, ci/**, .preview/**).
  • Вручную — 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) и прикрепляются к запуску workflow как артефакт 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

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

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

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

5. Релизы по тегу

Пуш тега v1.0.0 или companion-v1.0.0 собирает набор и создаёт черновик релиза с прикреплёнными .bin / .uf2 / .zip. Версия берётся из тега (companion-v1.2.3 → v1.2.3) и попадает в имена файлов (<env>-v1.2.3-<sha>.uf2).

git tag companion-v1.0.0 && git push origin companion-v1.0.0
# затем: репозиторий → Releases → черновик → Publish

Публикация идёт автоматическим secrets.GITHUB_TOKEN (в workflow стоит permissions: contents: write). Если релизы не создаются — заведите секрет RELEASE_TOKEN с правом write:repository и подставьте его в шаге «Черновик релиза».

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

ci/build-firmwares.sh, массив DEFAULT_TARGETS: T096 (companion, repeater, room server, sensor), ProMicro (SSD1306, SH1106, repeater, room server), Heltec v3, heltec_v4 TFT, tracker_v2, T-Deck, T-Echo Card, T114, T190, M9 и три варианта Meshadventurer.

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

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

8. Грабли, на которые уже наступали

Симптом Причина и решение
.../bin/pip: No such file or directory venv создан без pip — нет python3-pip; поставить пакет, venv пересоздать
DEFAULT_ACTIONS_URL does not support "https://github.com" в Gitea 1.27 значение — github, не ссылка
раннер берёт задачи чужих репозиториев токен выдан без --scope owner/repo
registration file not found в цикле рестартов раннер запущен до регистрации: сначала register, потом сервис
E: Could not get lock /var/lib/dpkg/lock-frontend работает unattended-upgrades; подождать либо остановить apt-daily.timer
на push запускается сборка сотен env не выставлен WORKFLOW_DIRS = .gitea/workflows
405 Method Not Allowed при создании тега в Gitea тег создаётся через POST /repos/{owner}/{repo}/tags, у /git/refs метода POST нет
python3: command not found или пустой вывод в Git Bash это заглушка Microsoft Store; задайте PYTHON3=/c/.../python.exe (это делает ci/build-local.ps1)
в out/ оказались файлы только последней платы build.sh при каждом запуске делает rm -rf out; ci/build-firmwares.sh копит результат в dist/ и в конце складывает всё в out/
нужно опубликовать уже собранное, без пересборки ci/build-local.ps1 -SkipBuild -Publish -Tag <тег>