diff --git a/.gitea/workflows/firmware.yml b/.gitea/workflows/firmware.yml index 424cddb1..855cc526 100644 --- a/.gitea/workflows/firmware.yml +++ b/.gitea/workflows/firmware.yml @@ -61,6 +61,12 @@ jobs: run: | # отдельное venv: на свежих Debian/Ubuntu pip в систему запрещён (PEP 668) python3 -m venv "$HOME/.platformio-venv" + # venv из кэша может оказаться без pip (если на хосте не было python3-pip) — пересоздаём + if ! "$HOME/.platformio-venv/bin/pip" --version >/dev/null 2>&1; then + echo "venv без pip — пересоздаю" + rm -rf "$HOME/.platformio-venv" + python3 -m venv "$HOME/.platformio-venv" + fi "$HOME/.platformio-venv/bin/pip" install --upgrade pip platformio echo "$HOME/.platformio-venv/bin" >> "$GITHUB_PATH" diff --git a/ci/README.md b/ci/README.md index c5b324c0..2140a14f 100644 --- a/ci/README.md +++ b/ci/README.md @@ -1,6 +1,6 @@ # CI: автоматическая сборка прошивок на своём Gitea -Схема: **Gitea (systemd) → act_runner на том же сервере → PlatformIO → артефакты `out/`**. +Схема: **Gitea (systemd) → Gitea Runner на том же сервере → PlatformIO → артефакты `out/`**. Сборка идёт через `build.sh` из репозитория, то есть тем же путём, что и локально (версия прошивки, `merge-bin` для ESP32, `.uf2` для nRF52), — логика не дублируется. @@ -8,158 +8,161 @@ | Файл | Назначение | |---|---| -| `.gitea/workflows/firmware.yml` | workflow: клон, кэш PlatformIO, сборка, артефакты, черновик релиза по тегу | +| `.gitea/workflows/firmware.yml` | workflow: клон, кэш, сборка, артефакты, черновик релиза по тегу | | `ci/build-firmwares.sh` | сборка выбранного набора env (годится и для запуска руками) | -| `ci/act_runner/act-runner.service` | systemd-юнит раннера | +| `ci/act_runner/gitea-runner.service` | systemd-юнит раннера | | `ci/act_runner/config.yaml` | конфиг раннера: ёмкость, таймаут, кэш | | `ci/act_runner/docker-compose.yml` | альтернатива: раннер в Docker | -## 1. Что должно быть на VPS +## 1. Что должно быть на сервере ```bash apt-get update -apt-get install -y git python3 python3-venv python3-pip build-essential curl ca-certificates +apt-get install -y git python3 python3-venv python3-pip curl ca-certificates build-essential ``` -- `python3-venv` обязателен: workflow ставит PlatformIO в отдельное окружение - (`~/.platformio-venv`), потому что на свежих Debian/Ubuntu pip в систему запрещён. -- Свободного места нужно **5 ГБ**: `~/.platformio` с тулчейнами (~2–3 ГБ), - venv и промежуточные файлы сборки. -- RAM: 2 ГБ достаточно, при 1 ГБ возможны падения линковки ESP32. +- **`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 упирается в память: + ```bash + fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile + echo '/swapfile none swap sw 0 0' >> /etc/fstab + ``` -## 2. Установка раннера (systemd) +## 2. Включение Actions в Gitea + +В `/etc/gitea/app.ini` (владелец `git:git`, права 600): + +```ini +[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) ```bash -# отдельный пользователь, от его имени пойдут сборки useradd --create-home --home-dir /var/lib/act-runner --shell /bin/bash act-runner -# бинарник: актуальную версию и имя файла сверьте на -# https://gitea.com/gitea/act_runner/releases -# (в свежих релизах проект называется Gitea Runner, см. https://docs.gitea.com/runner/) -curl -fsSL -o /usr/local/bin/act_runner \ - https://gitea.com/gitea/act_runner/releases/download/v0.2.11/act_runner-0.2.11-linux-amd64 -chmod +x /usr/local/bin/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 -install -d /etc/act_runner -cp ci/act_runner/config.yaml /etc/act_runner/config.yaml - -# токен: Gitea → репозиторий → Settings → Actions → Runners → Create new Runner -su - act-runner -c 'act_runner register --no-interactive \ - --instance https://git.meshinfo.ru \ - --token ВСТАВИТЬ_ТОКЕН \ - --name meshcore-builder \ - --labels ubuntu-latest:host' - -# сервис -cp ci/act_runner/act-runner.service /etc/systemd/system/ -systemctl daemon-reload -systemctl enable --now act-runner -systemctl status act-runner -journalctl -u act-runner -f # в логах: "runner registered" / "polling tasks" +cp ci/act_runner/config.yaml /var/lib/act-runner/config.yaml +chown act-runner:act-runner /var/lib/act-runner/config.yaml ``` -Метка `ubuntu-latest:host` означает, что шаги выполняются **прямо на сервере** — быстро -и без Docker, но зависимости ставятся в систему. Метка должна совпадать с `runs-on` -в `.gitea/workflows/firmware.yml`. +**Токен — обязательно со scope репозитория.** Без `--scope` раннер становится глобальным +и начинает брать задачи **всех** репозиториев инстанса (в том числе чужие stale-bot): -Раннер виден в Gitea: репозиторий → Settings → Actions → Runners (должен быть зелёным). +```bash +# от имени пользователя 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. + +```bash +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 -Если на VPS есть Docker, из `ci/act_runner`: - ```bash -cd ci/act_runner -cat > .env <<'EOF' -GITEA_INSTANCE_URL=https://git.meshinfo.ru -GITEA_RUNNER_REGISTRATION_TOKEN=ВСТАВИТЬ_ТОКЕН -GITEA_RUNNER_NAME=meshcore-builder -EOF -docker compose up -d && docker compose logs -f +cd ci/act_runner && cp .env.example .env && nano .env && docker compose up -d ``` -В этом варианте job'ы идут в контейнере `catthehacker/ubuntu:act-22.04`, а docker.sock -смонтирован внутрь раннера. В свежих версиях образ может называться `gitea/runner`. - -## 3. Отключить лишние workflow - -Gitea читает workflow и из `.gitea/workflows`, и из `.github/workflows`, а там лежат -upstream-файлы с триггером `push`: `build-companion-firmwares.yml`, -`build-repeater-firmwares.yml`, `build-room-server-firmwares.yml`, `github-pages.yml`, -`run-unit-tests.yml`. На первом же пуше они попытаются собрать сотни env (в проекте их -около 600) или задеплоить Pages. - -Отключите их в настройках репозитория (раздел Actions) либо через API: - -```bash -curl -X POST -H "Authorization: token $GITEA_TOKEN" \ - https://git.meshinfo.ru/api/v1/repos/shade/MeshCore/actions/workflows/run-unit-tests.yml/disable -``` - -Оставьте включённым только `firmware.yml`. Если ваша версия Gitea поддерживает -настройку `actions.WORKFLOW_DIRS`, можно ограничить список каталогов одним -`.gitea/workflows` — тогда upstream-файлы не подхватятся вовсе. +В свежих версиях образ называется `gitea/runner` (раньше `gitea/act_runner`). ## 4. Запуск сборки - **Автоматически** — push в `main` (кроме изменений в `*.md`, `ci/**`, `.preview/**`). -- **Вручную** — Actions → Firmware build → Run workflow, поля: - - `targets` — env через запятую, например `Heltec_t096_companion_radio_ble,ProMicro_companion_radio_ble`; - - `match` — подстрока имени env, например `heltec_t096`; - - `version` — значение `FIRMWARE_VERSION` (по умолчанию `ci`). -- **Локально** — тот же скрипт, что запускает CI: - -```bash -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 -bash build.sh list | grep -i t096 # доступные env -``` +- **Вручную** — Actions → Firmware build → Run workflow (`targets`, `match`, `version`), + либо через API: + ```bash + 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: + ```bash + 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`. ## 5. Релизы по тегу -Пуш тега вида `v1.0.0` или `companion-v1.0.0` запускает сборку и **создаёт черновик -релиза** с прикреплёнными `.bin` / `.uf2` / `.zip`. Версия прошивки берётся из тега: -`companion-v1.2.3` → `v1.2.3`, и попадает в имена файлов -(`-v1.2.3-.uf2`). - -Черновик — чтобы можно было посмотреть состав и нажать Publish руками: +Пуш тега `v1.0.0` или `companion-v1.0.0` собирает набор и создаёт **черновик релиза** +с прикреплёнными `.bin` / `.uf2` / `.zip`. Версия берётся из тега +(`companion-v1.2.3` → `v1.2.3`) и попадает в имена файлов (`-v1.2.3-.uf2`). ```bash -git tag companion-v1.0.0 -git push origin companion-v1.0.0 +git tag companion-v1.0.0 && git push origin companion-v1.0.0 # затем: репозиторий → Releases → черновик → Publish ``` -Для публикации используется `secrets.GITHUB_TOKEN`, который Gitea выдаёт workflow -автоматически (в workflow стоит `permissions: contents: write`). Если по вашему -токену релизы не создаются, заведите секрет репозитория `RELEASE_TOKEN` с правом -`write:repository` и подставьте его в шаге «Черновик релиза». +Публикация идёт автоматическим `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. +`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. Время и ресурсы -- Первая (холодная) сборка набора — примерно 30–60 минут: скачиваются тулчейны. -- Последующие запуски заметно быстрее: `~/.platformio` и venv кэшируются между - запусками через `actions/cache`. -- `capacity: 1` в `config.yaml` — одна сборка за раз; поднимайте, если CPU позволяет. +- Сервер с **1 CPU / 2 ГБ RAM** полный набор собирает долго (первый прогон — часы), + и на время сборки Gitea с Postgres на той же машине заметно тормозят. + Разумно запускать полный набор вручную, а на push держать 2–3 env. +- Первая сборка качает тулчейны (nRF52: framework + CMSIS + gcc-arm ≈ 660 МБ; + ESP32 — ещё столько же), дальше работает кэш `~/.platformio`. +- `capacity: 1` в `config.yaml` — одна сборка за раз. -## Ограничения +## 8. Грабли, на которые уже наступали -- Шаги используют `actions/checkout`, `actions/cache`, `actions/upload-artifact`, - `actions/download-artifact`. Раннер скачивает их с GitHub (`DEFAULT_ACTIONS_URL`), - поэтому серверу нужен доступ в интернет; в закрытом контуре укажите свой миррор - экшенов в `config.yaml`. -- Кэш `~/.platformio` растёт со временем: если диск кончается, почистите - `~/.platformio/.cache` у пользователя `act-runner`. +| Симптом | Причина и решение | +|---|---| +| `.../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` | diff --git a/ci/act_runner/.env.example b/ci/act_runner/.env.example new file mode 100644 index 00000000..4c96b35c --- /dev/null +++ b/ci/act_runner/.env.example @@ -0,0 +1,4 @@ +# Скопируйте в .env и заполните (используется docker-compose.yml). +GITEA_INSTANCE_URL=https://git.meshinfo.ru +GITEA_RUNNER_REGISTRATION_TOKEN= +GITEA_RUNNER_NAME=meshcore-builder diff --git a/ci/act_runner/config.yaml b/ci/act_runner/config.yaml index 6dec6ae6..d47a3d04 100644 --- a/ci/act_runner/config.yaml +++ b/ci/act_runner/config.yaml @@ -1,27 +1,29 @@ -# Конфигурация act_runner (Gitea Actions). -# Подключается в docker-compose.yml как /config.yaml. +# Конфигурация Gitea Runner (бывший act_runner). +# +# Полный список опций с комментариями: gitea-runner config generate +# Этот файл читается сервисом: gitea-runner daemon -c /var/lib/act-runner/config.yaml +# Метки (labels) здесь не задаются — они фиксируются при регистрации раннера: +# gitea-runner register ... --labels ubuntu-latest:host log: level: info runner: - file: /data/.runner + file: /var/lib/act-runner/.runner capacity: 1 # одновременно одна сборка; поднимайте, если на VPS много CPU timeout: 5h # холодная сборка набора прошивок может идти долго fetch_timeout: 30s fetch_interval: 5s - # Метки не задаём здесь: они фиксируются при регистрации раннера - # (systemd: act_runner register --labels ubuntu-latest:host, - # docker: переменная GITEA_RUNNER_LABELS в docker-compose.yml) cache: enabled: true - dir: /data/cache + dir: /var/lib/act-runner/.cache/actcache host: "" port: 0 container: - # job'ы запускаются как sibling-контейнеры через смонтированный docker.sock + # в host-режиме (метка ubuntu-latest:host) контейнеры не используются, + # секция оставлена для варианта с Docker network: "" privileged: false options: "--add-host=host.docker.internal:host-gateway" diff --git a/ci/act_runner/docker-compose.yml b/ci/act_runner/docker-compose.yml index d8817f4e..9bceb2f7 100644 --- a/ci/act_runner/docker-compose.yml +++ b/ci/act_runner/docker-compose.yml @@ -1,22 +1,18 @@ -# act_runner для Gitea: выполняет Gitea Actions на этом сервере. +# Альтернатива systemd: раннер в Docker. +# В свежих релизах образ называется gitea/runner (раньше gitea/act_runner). # -# Запуск (из каталога ci/act_runner): -# 1) получить токен: Gitea → репозиторий → Settings → Actions → Runners → Create new Runner -# 2) создать .env рядом с этим файлом: -# GITEA_INSTANCE_URL=https://git.meshinfo.ru -# GITEA_RUNNER_REGISTRATION_TOKEN=<токен из шага 1> -# GITEA_RUNNER_NAME=meshcore-builder -# 3) docker compose up -d -# 4) проверить: docker compose logs -f +# 1) cp .env.example .env && nano .env # адрес Gitea и токен раннера +# 2) docker compose up -d +# 3) docker compose logs -f # ждём "declare successfully" # -# Метка ubuntu-latest должна совпадать с runs-on в .gitea/workflows/firmware.yml. -# Образ job'а — catthehacker/ubuntu:act-22.04: в нём уже есть git, curl, python3, -# build-essential; PlatformIO ставится шагом workflow и живёт в кэше. +# Токен берите со scope репозитория, иначе раннер будет брать задачи всех +# репозиториев инстанса: +# su - git -c "gitea actions generate-runner-token -c /etc/gitea/app.ini --scope shade/MeshCore" services: - act-runner: - image: gitea/act_runner:latest - container_name: meshcore-act-runner + runner: + image: gitea/runner:latest + container_name: meshcore-gitea-runner restart: unless-stopped environment: GITEA_INSTANCE_URL: ${GITEA_INSTANCE_URL:?укажите адрес Gitea в .env} @@ -25,7 +21,6 @@ services: GITEA_RUNNER_LABELS: ${GITEA_RUNNER_LABELS:-ubuntu-latest:docker://catthehacker/ubuntu:act-22.04} CONFIG_FILE: /config.yaml volumes: - # состояние раннера (.runner) и локальный кэш Gitea Actions - ./data:/data - ./config.yaml:/config.yaml:ro # job'ы запускаются как соседние контейнеры, поэтому нужен доступ к демону diff --git a/ci/act_runner/act-runner.service b/ci/act_runner/gitea-runner.service similarity index 60% rename from ci/act_runner/act-runner.service rename to ci/act_runner/gitea-runner.service index 2b951e1a..1e3e93e3 100644 --- a/ci/act_runner/act-runner.service +++ b/ci/act_runner/gitea-runner.service @@ -1,21 +1,20 @@ [Unit] Description=Gitea Actions runner (MeshCore firmware builder) -Documentation=https://docs.gitea.com/usage/actions/act-runner +Documentation=https://docs.gitea.com/runner/ After=network-online.target Wants=network-online.target [Service] Type=simple # отдельный пользователь: от его имени выполняются шаги workflow, -# здесь же живёт кэш PlatformIO +# здесь же живут кэш PlatformIO и venv User=act-runner Group=act-runner WorkingDirectory=/var/lib/act-runner Environment=HOME=/var/lib/act-runner -ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml +ExecStart=/usr/local/bin/gitea-runner daemon -c /var/lib/act-runner/config.yaml Restart=always RestartSec=5 -# сборка прошивок — процесс долгий и прожорливый, но не привилегированный NoNewPrivileges=true [Install]