Перед уроком
Обери свою групу й себе зі списку. Тоді відповіді й перевірки завдань запишуться саме на тебе.
Довести бота до стану, який не соромно показати: написати README для незнайомої людини, випустити версію 1.0 з описом і шляхом назад, перевірити проєкт власним скриптом-аудитом, прибрати з екрана секрети — і за дві-три хвилини розповісти про свою роботу гостям.
Замість <логін> підставляєш свій
логін виду bohdan.g9: ім’я, крапка, номер групи. Кутові дужки не пишуться.
У прикладах на цій сторінці скрізь стоїть bohdan.g9 — читай це як свій логін
і виправляй у кожній команді, яку копіюєш. Кабінет — сторінка, де проти кожного критерію
стоїть відмітка, зарахований він чи ні.
<домен> — назва, яку ти записав у файл
~/app/project.yaml на занятті 10, розділ server, поле
url. Сабдомен (із заняття 10) — це частина адреси перед
доменом: в імені bohdan.g9.klub.example домен — klub.example,
а сабдомен — bohdan.g9. Саме цю адресу ти сьогодні даєш гостям, тому перевір
її першою справою.
Перші два рядки ведуть на одне й те саме: за обома адресами nginx віддає
файли з твоєї теки ~/www. Бот у цьому не бере участі: він сам звертається
до Telegram.
Це останнє заняття курсу. За кілька місяців ти зібрав бота, який відповідає, пам’ятає людей, питає ШІ, шукає у своїй базі знань, пише першим і ловить власні помилки через тести. Тепер його треба випустити: так, щоб незнайома людина відкрила сторінку проєкту, за пів хвилини зрозуміла, що це, і змогла його запустити.
До кінця заняття в тебе буде:
README.md із сімома розділами, написаними твоїми словами;RELEASE.md: що входить у версію 1.0, які в неї є слабкі місця і як повернутися назад, якщо щось зламається;v1.0 на коміті, де всі тести зелені;audit.py — фінальний аудит: ти сам допишеш її, і вона за десять пунктів скаже, що вже готово (✔), а що ні (✘);/version, що показує, яка версія бота зараз працює;Якщо в тебе немає TelegramУсе, крім живого повідомлення, ти зробиш через try_bot.py. На виступі замість живого чату покажеш його (приклади є в кроці 13). Пункти, де потрібен живий бот, викладач оцінить окремо.
Поки ти пишеш бота, код змінюється щодня. Але щоб сказати комусь «ось готова штука», треба вирізати з цього потоку одну мить і домовитися: ось це — версія 1.0. Така мить називається релізом (випуском), а її позначка в Git — тегом. Тег — це наклейка на конкретному коміті: гілка рухається вперед із кожним новим комітом, а тег лишається на місці.
Навіщо це? Через тиждень ти виправиш щось і зламаєш. Тоді git checkout v1.0 покаже тобі код тієї версії, яку ти колись показував гостям і яка працювала. Після такого перегляду поверни робочу гілку: git switch main (Git скаже про «detached HEAD» — це лише означає, що ти дивишся на старий коміт, а не працюєш на гілці). А щоб справді позбутися поганих змін, є git revert: вона додає новий коміт, що їх скасовує. Це й називається відкат. Ще корисне правило: тег ставлять на коміті, де вже проходять тести, інакше «версія 1.0» — це версія з відомою поломкою.
До тега додають короткий файл RELEASE.md із трьома відповідями: що в цій версії (мовою користувача: «бот відповідає на /ask», а не «переписав функцію»), які в неї слабкі місця («без підключення до ШІ-шлюзу бот відповідає ввічливою відмовою») і як відкотитися. Написати про слабкі місця самому — нормально: так роблять усі дорослі проєкти, і так ти сам вирішуєш, що гість почує першим.
Ти поставив тег v1.0, а наступного дня змінив текст /help і зробив ще один коміт. Куди тепер вказує тег v1.0?
README — це перше, що бачить людина, відкривши репозиторій на GitHub. У неї є приблизно тридцять секунд. Якщо за цей час вона не зрозуміє, що це і чи їй це потрібно, — закриє вкладку. Тому README пишуть не для себе і не для викладача, а для незнайомої людини, яка про твій проєкт нічого не знає.
У шаблоні сім головних розділів, і кожен відповідає на одне питання:
| Розділ | Питання, на яке він відповідає |
|---|---|
| Що це | Що робить бот і яку проблему розв’язує? |
| Для кого | Хто ним користуватиметься і що йому стане зручніше? |
| Як запустити | Що зробити по кроках, щоб воно заробило? (токен, .env, перша перевірка) |
| Команди бота | Що можна написати боту? |
| Приклад розмови | Як це виглядає в житті? (шматок діалогу або знімок екрана) |
| Що вміє | Головні можливості списком |
| Чого я навчився | Що було важко, що вийшло, що зробиш інакше |
Тут можна попросити ШІ допомогти: «ось мій bot.py, запропонуй, як пояснити команди людині, що бачить бота вперше». Але розділ «Чого я навчився» мусить звучати твоїм голосом: його прочитають гості, і саме з нього видно, що проєкт зробив ти. До того ж автоперевірка шукає в розділах твій текст і справжні команди з твого bot.py, а не загальні фрази.
Пароль у README — ніколиУ README пишуть, що треба вписати в .env, але не самі значення. Токен бота у файлі, який лежить на GitHub, — це як лишити ключ від квартири в дверях.
Для кого ти пишеш README?
Чекліст — список справ, які треба перевірити перед важливою подією; так робить пілот перед зльотом. Перелік із десяти пунктів ми зробимо не на папері, а як програму — audit.py. Аудит — це перевірка за списком: програма проходить пункти й для кожного друкує ✔ (гаразд) або ✘ (є що виправити, і чому). Ось усі десять:
| № | Пункт | Звідки береться |
|---|---|---|
| 1 | README: сім розділів з твоїм текстом | вже написано |
| 2 | RELEASE.md: що в релізі, обмеження, як відкотитися | допишеш ти |
| 3 | тег v1.0 існує й стоїть на коміті з історії твоєї гілки main | вже написано |
| 4 | .env не потрапляв у git ні зараз, ні в історії | вже написано |
| 5 | .env.example: усі змінні з .env, але без значень | допишеш ти |
| 6 | бекап бази не старший за добу | вже написано |
| 7 | з бекапу вже відновлювались | вже написано |
| 8 | служба сама піднімається (Restart=always) | допишеш ти |
| 9 | ранковий звіт: таймер увімкнено | вже написано |
| 10 | усі тести проходять | вже написано |
Три пункти (2, 5 і 8) ти допишеш сам: у кожному стоїть заготовка «ще не написано», яку треба замінити своєю перевіркою. Правило одне: функція повертає "" (порожній рядок), якщо все гаразд, або речення про те, що не так.
Головна вимога до аудиту — правдивість. Аудит, який завжди каже ✔, гірший за відсутній: він дає хибний спокій, і ти йдеш на показ з відкритим токеном, думаючи, що все гаразд. Тому автоперевірка нижче на сторінці не просто запускає твій audit.py: вона перевіряє ті самі речі власним способом і порівнює. Якщо твій аудит каже ✔, а насправді не гаразд (або навпаки) — зараховано не буде.
audit.py друкує десять ✔, але команда git ls-files показує, що .env лежить у git. Що це означає?
На дні показу твій екран бачать десятки людей, а ще його можуть сфотографувати чи записати. Тому перед показом пройдися по короткому списку:
cat .env і не відкривай .env у редакторі. Перед виступом виконай clear, щоб прибрати зі стрічки термінала старі команди.audit.py каже ✔ у пунктах 4 і 5.try_bot.py. Заздалегідь зроби знімки екрана найголовніших відповідей.Після показу — змінити токен бота. Відкрий у Telegram @BotFather, напиши /revoke, вибери свого бота: старий токен перестане працювати, а BotFather видасть новий. Новий впиши в ~/app/.env і перезапусти службу. Навіщо, якщо ніби ніхто нічого не помітив? Заміна токена займає хвилину, а витік — це небезпека для всіх, хто писав боту: чужа людина зможе писати від імені твого бота і читати, що йому надсилають. Тому токен міняють після показу завжди, а не лише коли здається, що він «мигнув».
Під час показу токен бота на секунду з’явився на екрані проєктора. Що зробити після показу?
Виступ — дві-три хвилини, не більше. Це схоже на рекламний ролик: за короткий час треба розповісти, навіщо твоя річ існує, показати її в роботі і не загубитись. План з чотирьох частин:
| Частина | Скільки | Що сказати |
|---|---|---|
| 1. Проблема | 30 с | «Мене звати … Я зробив бота, який … Він потрібен, щоб …» |
| 2. Демо | 60–90 с | Показуєш бота в дії (порядок нижче) |
| 3. Як влаштовано | 30 с | «Бот — програма на Python, що живе на сервері як служба. Повідомлення приходить у handle_update, дані лежать у SQLite, а бекап і ранковий звіт запускають таймери» |
| 4. Чого навчився | 30 с | Одна річ, що вийшла, і одна помилка, яку виправив |
Порядок демо (п’ять кроків, щоб нічого не забути): 1) /start: бот вітається; 2) своя команда або /ask; 3) скрипт за розкладом або ранковий звіт; 4) відмова чужому: чужий номер пише /run privit і отримує «Ця команда лише для власника бота» — це видовищна частина, бо показує, що захист справжній; 5) /version: бот називає свою версію.
Правило виступу: репетируй уголос із секундоміром. Тихо прочитати в голові — це не репетиція; уголос ти одразу почуєш, де заплутався.
Куди рости. Ідеї для наступних проєктів, що спираються на те, що ти вже вмієш: бот-нагадувач про домашні завдання й контрольні; бот класу (розклад, оголошення, голосування); бот-вікторина з таблицею рекордів; моніторинг: бот пише, якщо твій сайт перестав відкриватись; бот-помічник з базою знань про твоє хобі (фільми, гра, спорт). Вчитися далі зручно з офіційної документації Python і Telegram Bot API, з безкоштовних курсів (Prometheus, Coursera), ютуб-каналів про Python, шкільних і студентських олімпіад та змагань з програмування.
Як зберегти бота після курсу. Важливо: акаунти й сервер школи можуть бути вимкнені, і бот на них зупиниться. Тому вже зараз у тебе є все, щоб його перенести:
git clone завантажить його на будь-яку машину);.env.example; значення (токен) ти знаєш або можеш отримати новий в @BotFather;~/backups/app-….db; його можна завантажити на свій комп’ютер командою scp із заняття 08.Куди переносити:
Що робити на новому місці, завжди однаково: поставити Python і потрібні бібліотеки, зробити git clone, створити .env із токеном, відновити базу з бекапу, зробити службу з Restart=always (як у club-bot.service), написати боту /start. Один токен — один працюючий бот: перш ніж вмикати нового, вимкни старого, інакше Telegram буде видавати помилку конфлікту.
Репетиція переїздуУ кроці 12 ти перевіриш, що проєкт збирається з нуля з репозиторію. Якщо там тести проходять — переїзд буде нудним, а це якраз найкраще.
| Слово | Що означає |
|---|---|
| реліз | Випуск версії: момент, коли «воно працює» фіксують і кажуть «це версія 1.0» |
| версія | Номер випуску: v1.0, потім v1.1, v2.0 тощо |
| тег | Наклейка в Git на конкретному коміті. Не рухається, коли з’являються нові коміти |
| відкат | Повернення до попередньої справної версії: найчастіше git revert (скасувати поганий коміт). git checkout v1.0 лише показує старий код |
| RELEASE.md | Файл про версію: що в ній, які слабкі місця, як повернутися назад |
| README | Сторінка проєкту для людини, яка бачить його вперше |
| чекліст | Список справ, які перевіряють перед важливою подією |
| аудит | Перевірка за списком. У нас — програма audit.py, що друкує ✔ чи ✘ для десяти пунктів |
.env.example | Зразок .env: ті самі змінні, але без значень. Його можна класти в Git |
/revoke | Команда @BotFather, що скасовує старий токен і видає новий |
| демо | Короткий показ проєкту в дії |
| VPS | Орендований віртуальний сервер, на який можна перенести бота |
ssh <логін>@91.219.61.4
cd ~/app
git status --short
systemctl --user is-active club-bot
/opt/club/venv/bin/python3 -m pytest -q
ls /opt/club/kurs/13/git status --short нічого не друкує — усе з попередніх занять збережено. Видно файли — git add -A і збережи комітом: git commit -m "Заняття 12: доробки";active — служба працює; inactive — systemctl --user start club-bot;14 passed (число залежить від твоїх тестів). Є failed — спершу виправ (заняття 12), реліз із червоним тестом нікому не потрібен;audit.py, bot.py, README.template.md, RELEASE.template.md.Домовленість про Python: усе, що запускає pytest (тести та audit.py), запускай через /opt/club/venv/bin/python3: лише там стоять потрібні пакети. try_bot.py, backup.py і restore.py працюють і з простим python3.
cp /opt/club/kurs/13/audit.py ~/app/
cd ~/app
/opt/club/venv/bin/python3 audit.pyПрограма надрукує десять рядків: ✔ 3. git-тег v1.0 … або ✘ 2. RELEASE.md … — ще не написано, а в кінці Готово: N з 10.. Наразі ✘ буде кілька: пункти 2, 5 і 8 завжди, бо це твої заготовки, плюс ті, до яких ми ще не дійшли (README, тег, можливо бекап). Це не помилка, а список роботи: до кінця заняття всі десять мають стати ✔. Іноді тести (пункт 10) йдуть пів хвилини — зачекай.
Відкрий ~/app/bot.py (nano ~/app/bot.py). Потрібні три невеликі вставки. Готовий зразок лежить у /opt/club/kurs/13/bot.py: це бот із заняття 11 плюс /version. Але не копіюй його поверх свого файлу: у твоєму bot.py є свої правки. Порівняй: diff ~/app/bot.py /opt/club/kurs/13/bot.py і дивись лише на рядки про version.
Вставка 1. Знайди в bot.py текст HELP. Новий рядок має стати останнім у ньому. Після заняття 10 останній рядок — про /forget: у ньому лишається \n" без закривної дужки, а дужка ) переходить на новий рядок:
"/forget — видалити мої дані\n"
"/version — яка версія бота працює")Якщо в тебе інша остання команда, правило те саме: попередній рядок закінчується на \n", а ) стоїть лише після рядка про /version.
Вставка 2. У handle_update, одразу після гілки /whoami:
if text.startswith("/version"): # заняття 13
return version()Вставка 3. Нова функція перед def answer. Вона питає в git, на якому ти тегу, і повертає це як відповідь на /version:
def version():
"""Яка версія працює — за найближчим git-тегом (v1.0, v1.1…)."""
import subprocess
try:
r = subprocess.run(["git", "--no-optional-locks", "-C", str(BASE), "describe", "--tags", "--match", "v[0-9]*", "--always"],
capture_output=True, text=True, timeout=5)
tag = r.stdout.strip() if r.returncode == 0 else ""
except (OSError, subprocess.SubprocessError):
tag = ""
if not tag:
return "Версію визначити не вдалося: у ~/app немає git-репозиторію."
return f"Версія бота: {tag}"cd ~/app
python3 try_bot.py "/version"Тега ще немає, тому бот відповість коротким номером коміту, наприклад Версія бота: 1a2b3c4. Після тега в кроці 11 тут з’явиться v1.0. Бачиш Traceback — найчастіше пропущена дужка чи відступ у вставці; diff покаже, де.
cd ~/app
cp README.md README.old.md
cp /opt/club/kurs/13/README.template.md README.md
nano README.mdСтарий README збережено як README.old.md: бери з нього свої готові тексти (розділи «Що це» і «Як запустити» із заняття 03). У шаблоні в кожному розділі є рядок-підказка зі словом TODO. Правило: рядок із TODO видали й напиши замість нього своє. Вимоги такі:
`/help`);- .Розділ ## Персональні дані із заняття 10, якщо ти його писав, не видаляй: перенеси його нижче, перед розділом «Версії».
Як користуватися ШІМожна попросити його переглянути, чи зрозуміло написано «Як запустити», і де лишилися складні слова. Писати розділ «Чого я навчився» за тебе — не можна: його читатимуть гості, і він має бути твоїм.
rm README.old.md
grep -c "TODO" README.md
/opt/club/venv/bin/python3 audit.py | head -1Друга команда має надрукувати 0: це кількість рядків із TODO, що лишилися. Не нуль — відкрий файл і знайди їх. Третя покаже перший рядок аудиту: ✔ 1. README: сім розділів з твоїм текстом. Якщо там ✘, у кінці рядка видно причину: яка секція порожня чи якого розділу немає.
Нова людина, яка завантажить твій код, не знає, які змінні вписувати в .env. Для цього є зразок без значень. Назви змінних візьмемо з твого .env, не показуючи значень:
cd ~/app
grep '=' .env | cut -d= -f1 | sed 's/$/=/' > .env.example
cat .env.example
git check-ignore .env && echo ".env у git не потрапить"
git add .env.exampleДруга команда (cat) покаже щось на зразок BOT_TOKEN=, ADMIN_IDS=, LLM_BASE_URL= — назви з порожнім місцем після =. Третя (git check-ignore) друкує .env і наш напис — отже, .gitignore справді приховує файл. Не надрукувалось — додай рядок .env у .gitignore. Четверта додала зразок до наступного коміту.
cp /opt/club/kurs/13/RELEASE.template.md ~/app/RELEASE.md
date +%d.%m.%Y
nano ~/app/RELEASE.mdЗаміни ДД.ММ.РРРР на дату (її показала друга команда), а в кожному розділі видали рядки з TODO і напиши своє:
- , мовою користувача (не «переписав функцію», а «бот відповідає на /ask»);grep -c "TODO" ~/app/RELEASE.mdЗнову має бути 0.
Відкрий nano ~/app/audit.py і знайди функції, де стоїть return "ще не написано (ЗАПОВНИ)". Подивись, як написана перевірка tag() чи backup_fresh(): вона бере факт, порівнює його з вимогою й повертає "" або причину. За тим самим зразком напиши свої три. Перша, пункт 8, розібрана повністю — перенеси її:
@check("служба сама піднімається: Restart=always")
def restart_always():
unit = UNITS / "club-bot.service"
if not unit.exists():
return "немає файлу club-bot.service"
# рядок цілком: закоментований «# Restart=always» не годиться
if not re.search(r"^\s*Restart\s*=\s*always\s*$", unit.read_text(encoding="utf-8"), re.M):
return "у club-bot.service немає рядка Restart=always"
return ""Дві інші перевірки — за тим самим зразком. Значення змінних із .env не друкуй і не повертай у причині.
release_notes). Візьми текст RELEASE.md; перевір, що в ньому немає слова TODO; для «Що в релізі» (потрібно три пункти) і «Відомі обмеження» (два) порахуй рядки, що починаються з - ; у «Як відкотитися» знайди git revert або git reset. Якщо щось не так — поверни речення про це, інакше "".env_example). Перевір, що .env.example існує й лежить у git; що в ньому є всі назви змінних з .env; що значення коротші за 30 символів (довше — схоже на справжній токен).Застряг — подивись розв’язки в розділі «Якщо щось не працює» внизу, після спроби самому.
cd ~/app
/opt/club/venv/bin/python3 audit.pyПісля виправлення пункти 2, 5 і 8 мають стати ✔, а на місці «ще не написано» не лишитись нічого. Якщо перевірка «впала» — з’явиться перевірка впала: NameError (чи інша назва): значить, у твоїй функції описка.
cd ~/app
python3 backup.py
python3 restore.py
ls -l ~/backups | tail -3
ls -l ~/restore-test/
systemctl --user is-enabled club-backup.timerbackup.py друкує шлях нового файлу app-ДАТА.db; restore.py розгортає найсвіжіший бекап у ~/restore-test/app.db й перелічує таблиці (це не чіпає робочу базу). Остання команда має сказати enabled. Інакше: systemctl --user enable --now club-backup.timer (заняття 08). Бекап, з якого жодного разу не відновлювались, — не бекап; тому обидва кроки в одному місці.
grep -n Restart ~/.config/systemd/user/club-bot.service
systemctl --user is-enabled club-morning.timer
systemctl --user list-timers club-morning.timerПерша команда має показати рядок Restart=always («завжди перезапускай службу, якщо вона впала»). Друга — enabled. Третя показує, коли таймер спрацює наступного разу: стовпець NEXT (час за сервером, а не за Києвом — це та сама мить, що о 08:00 у Києві). Чого бракує — зроби кроки із занять 08–09, наприклад: systemctl --user enable --now club-morning.timer.
cd ~/app
/opt/club/venv/bin/python3 audit.pyТепер усі пункти, крім 3 (тег), мають бути ✔. Дивись на причину біля кожного ✘ і виправляй. Якщо пункт 4 (.env не потрапляв у git) ✘ через історію git, самому його не виправити (див. нижче «Якщо щось не працює», L13.5): скажи викладачеві.
cd ~/app
git status --short
git add -A
git commit -m "Заняття 13: README, RELEASE.md, audit.py, .env.example, /version"
git tag -a v1.0 -m "Реліз 1.0"
git push origin main
git push github main
git push origin v1.0
git push github v1.0
bash deploy.sh
python3 try_bot.py "/version"
/opt/club/venv/bin/python3 audit.pygit status --short має показати твої нові й змінені файли й не показати .env (інакше зупинись!). git tag -a створює тег із повідомленням і датою, а не лише голу наклейку. Кожен git push закінчується рядком main -> main чи * [new tag] v1.0 -> v1.0. deploy.sh (заняття 12) проганяє тести й перезапускає службу, щоб у Telegram з’явилась команда /version. Далі бот відповідає Версія бота: v1.0, а аудит — Готово: 10 з 10..
master? Пиши master замість main.git tag -fa v1.0 -m "Реліз 1.0" і git push -f origin v1.0. Прапорець -f тут лише для тега: гілку так надсилати не можна. Якщо сервер відмовив — скажи викладачеві.deploy.sh? Просто systemctl --user restart club-bot./version покаже щось на кшталт v1.0-1-g1a2b3c4: «версія 1.0 і ще один коміт зверху». Це нормально.git clone ~/repo.git ~/clone-test
cd ~/clone-test
git tag
ls -a
BOT_POLLING=0 /opt/club/venv/bin/python3 -m pytest -q
cd ~
rm -rf ~/clone-testТи щойно зробив те, що робитиме людина на новому комп’ютері: завантажив код «з нуля». git tag покаже v1.0. У списку файлів ls -a має бути код, README.md, .env.example, але не .env і не база — їх не мало бути в репозиторії. Тести в копії мають пройти (N passed). Якщо тест упав на ModuleNotFoundError або No such file — значить, якийсь файл існує лише в тебе й не доданий у git: додай його в справжньому ~/app командою git add, збережи комітом, поправ тег (крок 11) і повтори. Без такого файлу переїзд на новий сервер був би сюрпризом.
nano ~/app/VYSTUP.mdЗапиши чотири частини плану з теорії (Проблема, Демо, Як влаштовано, Чого навчився) — по 2–3 речення своїми словами. Поряд пропиши сценарій демо з п’яти кроків:
1. /start
2. /ask що таке API? (або своя команда)
3. ранковий звіт або скрипт за розкладом
4. чужий номер: python3 try_bot.py --id 999 "/run privit" → «Ця команда лише для власника бота.»
5. /version → v1.0 (або v1.0-N-g…, якщо після релізу були коміти)Прорепетируй п’ять кроків через try_bot.py — він працює й без Telegram:
python3 try_bot.py "/start";python3 try_bot.py "/ask що таке API?". Якщо ШІ-шлюз не підключено, бот відповість ввічливою відмовою — так і має бути, покажи її як є;OWNER_CHAT_ID=777 python3 try_bot.py --id 777 "/scripts" (777 — умовний номер власника);python3 try_bot.py --id 999 "/run privit" має отримати відмову;python3 try_bot.py "/version": v1.0 або v1.0-N-g… (v1.0 і ще N комітів зверху).Відповіді мають збігатися з тим, що ти пишеш у сценарії. Тепер уголос, із секундоміром: у ліміт 2–3 хвилини? Забагато — прибери деталі, лишивши ті, що ти справді хочеш, щоб гості запам’ятали.
Пройдися чеклістом із теорії (розділ 4) перед виходом на сцену: clear у терміналі; .env не відкрито; Telegram-чат без особистих повідомлень; запасні знімки екрана зроблено. А тепер допиши в кінець VYSTUP.md три рядки, які виконаєш одразу після показу:
Після показу:
1. @BotFather → /revoke → мій бот → новий токен
2. nano ~/app/.env (замінити BOT_TOKEN) → systemctl --user restart club-bot
3. написати боту /start і побачити відповідьНе виконуй їх зараз: токен міняємо після показу, щоб бот не замовк посеред виступу. Після зміни старий токен перестає діяти негайно, тож бот мовчатиме, доки не впишеш новий і не перезапустиш службу — так і має бути.
cd ~/app
git add VYSTUP.md
git commit -m "Заняття 13: план виступу і дня показу"
git push origin main
git push github main
git push github v1.0Відкрий у браузері свій репозиторій на GitHub. Перевір: у README.md правильно показуються всі розділи; гілка (кнопка зліва зверху) відкриває список тегів, де є v1.0; у налаштуваннях (Settings, внизу) видно, що репозиторій Private; файлу .env у списку немає. За бажанням на сторінці репозиторію натисни Releases → Create a new release, вибери тег v1.0 і встав текст з RELEASE.md: так реліз матиме власну сторінку. Якщо в тебе працює GitHub Actions (заняття 12), біля коміту з тегом має бути зелена галочка.
Автоперевірка нічого не змінює в твоєму репозиторії й нічого не шле в Telegram. Вона читає README.md і RELEASE.md і дивиться, чи там твій текст, а не шаблон: рядки, які ти не змінив, не рахуються. Перевіряє, що тег v1.0 стоїть на коміті, де проходять тести, і що тег відправлено в ~/repo.git. Запускає твій audit.py і порівнює його відповіді зі своїми: аудит, який каже ✔ там, де не гаразд (або навпаки), не зараховується. Шукає токени й секрети в файлах та в усій історії git. Дивиться бекап, відновлення, Restart=always і таймер ранкового звіту. Виступ і демо оцінює викладач.
Натисни «Перевірити практичну частину» в розділі «Перевірка виконаних завдань» нижче на сторінці. Перевірка тега й аудиту займає до півтори хвилини — зачекай.
| Код | Що перевіряється | Якщо не зараховано |
|---|---|---|
| L13.1 | README: сім розділів з твоїм текстом і справжніми командами автоперевірка | У ~/app/README.md мають бути розділи «Що це», «Для кого», «Як запустити», «Команди бота», «Приклад розмови», «Що вміє», «Чого я навчився», у кожному щонайменше 40 символів твого тексту і кілька різних слів (рядки з TODO видали, незмінені рядки шаблону не рахуються). У «Команди бота» назви щонайменше 4 справжні команди з твого бота у зворотних лапках, напр. `/help`; у «Що вміє» — 3 різні пункти «- …». |
| L13.2 | тег v1.0: на коміті проходять тести, тег відправлено автоперевірка | Тег має стояти на коміті, де вже є тека tests і всі тести зелені, та бути відправлений у ~/repo.git. Якщо тег поставлено зарано: git tag -fa v1.0 -m "Реліз 1.0" (на правильному коміті), git push -f origin v1.0 (-f лише для тега). Початково: git tag -a v1.0 -m "Реліз 1.0" && git push origin v1.0 |
| L13.3 | RELEASE.md: що в релізі, обмеження, як відкотитися автоперевірка | У ~/app/RELEASE.md: заголовок «# Реліз v1.0», розділ «Що в релізі» (≥3 різні пункти «- …»), «Відомі обмеження» (≥2 різні пункти), «Як відкотитися» з командою git revert або git reset і твоїм реченням про перевірку відкату. Усі рядки з TODO видали. |
| L13.4 | audit.py дописаний, друкує 10 пунктів і не бреше автоперевірка | Скопіюй /opt/club/kurs/13/audit.py у ~/app і допиши три перевірки (пункти 2, 5, 8): прибери рядки return "ще не написано…". Аудит має надрукувати рівно десять рядків «✔ N. …»/«✘ N. …»; перевірка порівнює їх із власною — якщо аудит каже ✔ там, де не гаразд (або навпаки), він не зарахується. У повідомленні вказано пункт і причину: підправ саме цю перевірку (а якщо причина в RELEASE.md чи README, спершу виправ їх: цим займаються L13.1 і L13.3). |
| L13.5 | секретів немає ні в коді, ні в історії git; є .env.example автоперевірка | Токен і інші секрети не мають бути в жодному файлі git і жодному коміті, а .env має ігноруватися (токена Telegram у .env може й не бути). Заміни .env.example (git add .env.example): ті самі змінні, що в .env, але без значень. Якщо токен колись потрапив у коміт — @BotFather → /revoke, новий токен у .env; історію чистить викладач. |
| L13.6 | свіжий бекап (до доби) і відновлення перевірено автоперевірка | Потрібні: таймер бекапу (systemctl --user enable --now club-backup.timer), копія в ~/backups молодша за 24 години (python3 backup.py) і python3 restore.py, що створює ~/restore-test/app.db. Бекап, з якого не відновлювались, — не бекап. |
| L13.7 | служба сама перезапускається, ранковий таймер увімкнено автоперевірка | У ~/.config/systemd/user/club-bot.service має бути рядок Restart=always (після змін: systemctl --user daemon-reload і systemctl --user restart club-bot). Таймер ранкового звіту: systemctl --user enable --now club-morning.timer |
| L13.8 | виступ на дні показу: 2–3 хвилини за планом (проблема, демо, як влаштовано, чого навчився) викладач | Позначку ставить викладач на занятті або після нього. |
| L13.9 | демо живого бота пройшло за сценарієм (/start, команда, розклад, відмова чужому, звіт) або показано запасний варіант викладач | Позначку ставить викладач на занятті або після нього. |
Кожне питання оцінюється відразу в браузері — це лишається так само. Ця кнопка лише надсилає підсумок учителю, щоб відповіді не зникли разом із закритою вкладкою.
Список критеріїв і що саме вони означають — у таблиці вище, «Що перевіряє автоматика». Тут — та сама перевірка, але прямо зараз, без очікування на найближчий прохід за розкладом.
## Що далі з трьома ідеями, куди рости (теорія, розділ 6). Одна з них має бути з нового для тебе: нова команда, інший сервіс, інша мова.VYSTUP.md: /revoke у @BotFather, новий токен у .env, перезапуск, /start. Запиши в VYSTUP.md, о котрій годині це зробив.git add -A, git commit -m "Заняття 13: домашня робота", git push origin main і git push github main.немає розділу «## Для кого» (чи іншого) — заголовок має бути рівно з двома символами # і пробілом: ## Для кого, без двокрапки на кінці;замало твого тексту — у розділі лишилися рядки з TODO, незмінені рядки шаблону або менш як 40 символів твого тексту. grep -n "TODO" ~/app/README.md покаже, де саме;мало різних слів — розділ складається з повторів одного слова; напиши речення своїми словами;названо справжніх команд 2, треба щонайменше 4 — пиши команди у зворотних лапках, як `/help`, і лише ті, що є в твоєму боті (/start, /help, /ask, /whoami, /version…);«Що вміє» менше трьох різних пунктів — кожен пункт з нового рядка, що починається з - (дефіс і пробіл), і складається щонайменше з двох слів.тега v1.0 немає — git tag -a v1.0 -m "Реліз 1.0";на коміті v1.0 немає теки tests — тег поставлено раніше за заняття 12 (або тести не додано в git: git ls-files tests). Збережи тести комітом і перенеси тег: git tag -fa v1.0 -m "Реліз 1.0";тести не проходять — git stash (сховати зміни), git checkout v1.0, BOT_POLLING=0 /opt/club/venv/bin/python3 -m pytest -q, подивись помилку; поверни робочу гілку: git switch main, git stash pop. Виправ на головній гілці, збережи комітом і перенеси тег;тег v1.0 не відправлено — git push origin v1.0 (після перенесення тега: git push -f origin v1.0, -f лише для тега, не для гілки);тег стоїть не на цій гілці — тег поставлено на коміті з іншої гілки (наприклад, на тій, де ти щось пробував). Перенеси тег на поточний коміт: git tag -fa v1.0 -m "Реліз 1.0".на початку RELEASE.md немає версії v1.0 — перший рядок має бути # Реліз v1.0;менше 3 різних пунктів (чи 2 у «Відомі обмеження») — пункти рядками, що починаються з - , не коротші за 12 символів і з двох слів і більше, без TODO; однакові пункти рахуються за один;немає команди git revert або git reset — у розділі «Як відкотитися» вона є в шаблоні, не видаляй;немає твого речення про перевірку відкату — допиши в «Як відкотитися» своє речення, як ти переконаєшся, що відкат вдався;лишились рядки заготовки TODO — grep -n "TODO" ~/app/RELEASE.md.лишилась заготовка «ще не написано» — у функціях пунктів 2, 5 і 8 прибери рядок return "ще не написано (ЗАПОВНИ)" і напиши перевірку;має надрукувати рівно 10 рядків — не видаляй і не додавай перевірок у списку, їх має бути десять: у кожної є @check(...) над def;audit.py поставив ✔ біля пункту N, а насправді не гаразд: … — після двокрапки названо причину, яку побачила автоперевірка. Твоя перевірка занадто поблажлива: додай до неї саме цю умову. Навпаки (✘, хоча все гаразд) — вона занадто сувора чи хибна; f = APP / "RELEASE.md"
if not f.exists():
return "немає RELEASE.md"
text = f.read_text(encoding="utf-8")
if "TODO" in text:
return "у RELEASE.md лишились рядки заготовки TODO"
for title, need in (("Що в релізі", 3), ("Відомі обмеження", 2)):
body = section(text, title)
if body is None:
return f"немає розділу «## {title}»"
points = [l for l in own_text(body).splitlines() if l.startswith("- ") and len(l) > 12]
if len(points) < need:
return f"у «{title}» менше {need} пунктів"
body = section(text, "Як відкотитися")
if body is None:
return "немає розділу «## Як відкотитися»"
return "" if re.search(r"git (revert|reset)", body) else "у «Як відкотитися» немає git revert чи git reset" f = APP / ".env.example"
if not f.exists():
return "немає .env.example"
if not run("git", "ls-files", ".env.example")[1]:
return ".env.example не додано в git"
names = {}
for line in f.read_text(encoding="utf-8").splitlines():
if "=" in line and not line.startswith("#"):
k, v = line.split("=", 1)
names[k.strip()] = v.strip()
for line in (APP / ".env").read_text(encoding="utf-8").splitlines():
if "=" in line and not line.startswith("#"):
k = line.split("=", 1)[0].strip()
if k not in names:
return f"у .env.example бракує {k}"
return "" if all(len(v) <= 30 for v in names.values()) else "у .env.example схоже на справжнє значення".gitignore не приховує .env — додай рядок .env у ~/app/.gitignore; а якщо .env уже відстежується: git rm --cached .env, збережи комітом;немає .env.example — крок 5, не забудь git add .env.example;значення секрету з .env є в історії git (коміт …) — токен (чи інший секрет) колись потрапив у коміт, і з історії він сам не зникне. Заміни токен: @BotFather → /revoke, новий — у .env, перезапуск служби. Історію чистить викладач: самому цей пункт не виправити;щось схоже на токен бота — у файлі, який потрапив у git (README, тест, bot.py), чи в старому коміті є рядок виду 123456789:AAH…. Прибери його, збережи комітом, а токен вважай скомпрометованим — як у попередньому пункті..env? Це не помилка: перевірка тоді шукає лише рядки, схожі на токен, і дивиться на .gitignore та .env.example.таймер club-backup.timer не ввімкнено — systemctl --user enable --now club-backup.timer;найсвіжішій копії N год — таймер не працює або ввімкнули нещодавно: python3 backup.py зробить копію зараз;у копії таблиця порожня — у базі немає жодного запису: напиши боту /start або python3 try_bot.py "/start", потім знову python3 backup.py;немає ~/restore-test/app.db — python3 restore.py.у club-bot.service немає рядка Restart=always — відкрий nano ~/.config/systemd/user/club-bot.service, у розділі [Service] додай Restart=always; тоді systemctl --user daemon-reload і systemctl --user restart club-bot;таймер ранкового звіту не ввімкнено — systemctl --user enable --now club-morning.timer;немає club-morning.timer — файли з заняття 09 не скопійовано: cp /opt/club/kurs/09/club-morning.* ~/.config/systemd/user/, daemon-reload, enable --now.