From eb7ac3d326f4d4441e21ac208c7eaddc4525759d Mon Sep 17 00:00:00 2001 From: bot-backend Date: Sun, 16 Aug 2026 10:07:39 +0300 Subject: [PATCH] =?UTF-8?q?fix(ci):=20=D0=B3=D0=B5=D0=B9=D1=82=20Caddyfile?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D0=BC=D0=BE=D0=B3=20=D0=BF=D1=80=D0=BE=D1=87?= =?UTF-8?q?=D0=B8=D1=82=D0=B0=D1=82=D1=8C=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8?= =?UTF-8?q?=D0=B3=20=E2=80=94=20`-v=20$PWD`=20=D0=B8=D0=B7=20job-=D0=BA?= =?UTF-8?q?=D0=BE=D0=BD=D1=82=D0=B5=D0=B9=D0=BD=D0=B5=D1=80=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Первая версия шага смонтировала `$PWD` внутрь caddy-контейнера и упала на `open /etc/caddy/Caddyfile: no such file or directory`. Причина: job сам исполняется внутри контейнера, а `docker run` создаёт КОНТЕЙНЕР-БРАТ на том же демоне. Путь в `-v` резолвится на ХОСТЕ, тогда как `$PWD` — путь внутри job-контейнера, которого на хосте нет. Классическая ловушка docker-in-docker, и она не зависит от содержимого конфига — смонтируй так что угодно, монтирования просто не произойдёт. Заменено на `docker create -w /work` + `docker cp` + `docker start -a`: копия не зависит от того, как смонтирован workspace. Копируется и каталог `caddy/` — Caddyfile делает `import caddy/users.caddy.snippet`, без него validate падает на импорте. Проверено локально обе стороны: валидный конфиг → `Valid configuration`, exit 0; конфиг с незакрытой скобкой → `unexpected EOF`, exit 1. Без второй проверки гейт мог бы оказаться вечно-зелёным. --- .forgejo/workflows/ci.yml | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/.forgejo/workflows/ci.yml b/.forgejo/workflows/ci.yml index 0fd47b82..c29ee38d 100644 --- a/.forgejo/workflows/ci.yml +++ b/.forgejo/workflows/ci.yml @@ -78,16 +78,31 @@ jobs: # obsidian, status. То есть цена опечатки в этом файле — полный # даунтайм, а гейта на неё не было. # - # `docker run`, а не установка caddy в раннер: тот же образ `caddy:2`, - # что стоит в docker-compose.prod.yml — проверяем ровно тем парсером, - # который будет читать конфиг на проде. Docker на раннере есть (им же - # поднимается Postgres в ci-tradein.yml). + # `docker cp`, а НЕ `-v "$PWD:/etc/caddy"`. Job сам исполняется внутри + # контейнера, и `docker run` создаёт КОНТЕЙНЕР-БРАТ на том же демоне: + # путь в `-v` резолвится на ХОСТЕ, а `$PWD` — это путь внутри job- + # контейнера, которого на хосте нет. Первая версия этого шага так и + # упала: `open /etc/caddy/Caddyfile: no such file or directory`. + # Копирование не зависит от того, как смонтирован workspace. + # + # Образ тот же `caddy:2`, что в docker-compose.prod.yml — проверяем ровно + # тем парсером, который будет читать конфиг на проде. + # + # Копируем и `caddy/` — Caddyfile делает `import caddy/users.caddy.snippet`, + # и без него validate упадёт на импорте (файл в репозитории есть). # # Плейсхолдеры окружения ({env.*}) при validate резолвятся в пустую # строку — это нормально, синтаксис от их значений не зависит. run: | - docker run --rm -v "$PWD:/etc/caddy" caddy:2 \ - caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile + set -euo pipefail + cid=$(docker create -w /work caddy:2 \ + caddy validate --config /work/Caddyfile --adapter caddyfile) + docker cp Caddyfile "$cid:/work/Caddyfile" + docker cp caddy "$cid:/work/caddy" + rc=0 + docker start -a "$cid" || rc=$? + docker rm -f "$cid" >/dev/null + exit "$rc" - name: "Guard: блокирующий DDL без lock_timeout (#2752)" # Тем же шагом-соседом и по той же причине: гейт бежит на КАЖДОМ PR,