Как CI/CD три дня молчал в Telegram, а я не замечал
Идеальная автоматизация — та, которую ты проверяешь только когда что-то пошло не так.
Сегодняшняя история про то, как я настроил пайплайн деплоя блога, добавил отправку уведомлений о новых постах в Telegram-канал, увидел в логах [notify-telegram] No new blog posts found. и подумал: «Ну нет новых постов, значит всё ок».
Прошло три дня.. Два поста опубликованы на сайте. В канале — тишина.
Как это работало (в теории)
После каждого пуша в main GitHub Actions делал следующее:
- Проверял типы и картинки
- Собирал Docker-образ и пушил в GHCR
- Деплоил на VPS
- Запускал
node scripts/notify-telegram.js
Скрипт нотификации брал git diff --name-only --diff-filter=A HEAD~1 HEAD, искал .md файлы в src/content/blog/, парсил frontmatter и отправлял пост в канал.
Выглядит логично, правда?
Как это работало (на практике)
А на практике HEAD~1 HEAD смотрит только на последний коммит. Если я запушил три коммита — с постом, с фиксом типографики и с обновлением зависимостей — то скрипт проверял diff только между фиксом и обновлением зависимостей. Пост оставался невидимым.
Ещё веселее: GitHub Actions с fetch-depth: 2 грузил всего два последних коммита. Если в них не было .md — скрипт благополучно ничего не находил и завершался с кодом 0. CI был зелёным. Всё хорошо. Никаких ошибок.
Самый опасный баг — тот, который не ломается, а просто молча не работает.
Отладка
Я обратил внимание только когда логи внезапно стали слишком короткими. Зашёл в Actions, открыл последний ран — notify-telegram отработал за 2 секунды и вывел:
[notify-telegram] No new blog posts found.
При этом на сайте уже висели два свежих поста.
Проблема оказалась в двух местах:
- Логика range:
HEAD~1 HEADвместо range от предыдущего пуша до текущего - Shallow clone:
fetch-depth: 2не давал истории для нормального diff
Что починил
Вместо HEAD~1 HEAD — использую GITHUB_EVENT_BEFORE и GITHUB_SHA:
git diff --name-only --diff-filter=A \
${GITHUB_EVENT_BEFORE}..${GITHUB_SHA} \
-- src/content/blog/
Вместо fetch-depth: 2 — поставил fetch-depth: 0 в checkout-шаге. Для небольшого репозитория разницы во времени нет, а diff работает корректно.
Ещё добавил возможность ручной отправки через FORCE_POST_FILE, на случай если нужно запостить что-то без коммита.
Что в итоге
Сейчас пайплайн видит все новые посты во всём range пуша, а не только в последнем коммите. И отправляет их все, если вдруг кто-то решит запушить несколько постов разом.
Проверяйте автоматизацию не по цвету галочки, а по результату. Зелёный CI — это хорошо, но зелёный CI с пустым каналом — это просто красиво оформленное молчание.