{"meta":{"title":"Диагностика сбоев тестов CI","intro":"Используйте Copilot CLI для извлечения CI-логов, сопоставления сбоев с локальным кодом и устранения проблем без выхода из терминала.","product":"GitHub Copilot","breadcrumbs":[{"href":"/ru/copilot","title":"GitHub Copilot"},{"href":"/ru/copilot/tutorials","title":"Учебники"},{"href":"/ru/copilot/tutorials/copilot-cookbook","title":"Кулинарная книга GitHub Copilot"},{"href":"/ru/copilot/tutorials/copilot-cookbook/debug-errors","title":"Ошибки отладки"},{"href":"/ru/copilot/tutorials/copilot-cookbook/debug-errors/diagnose-ci-test-failures","title":"Диагностика неудач тестов CI"}],"documentType":"article"},"body":"# Диагностика сбоев тестов CI\n\nИспользуйте Copilot CLI для извлечения CI-логов, сопоставления сбоев с локальным кодом и устранения проблем без выхода из терминала.\n\nCopilot CLI поставляется вместе с GitHub MCP сервером, который даёт ему прямой доступ к вашим GitHub Actions рабочим процессам, журналам заданий и статусам проверок. В сочетании с доступом к вашим локальным файлам он может получать детали отказа CI, сопоставлять их с вашим кодом и предлагать исправления с терминала.\n\n## Пример сценария 1: тесты проходят локально, но не проходят CI\n\nУ вас есть тест, который проходит на вашем локальном компьютере, но проваливается в CI. Вы можете попросить Copilot CLI расследовать этот провал теста напрямую.\n\nВ этом примере тестируемый код определяет простой сервис заказов (`order.py`), и есть соответствующий тест, который проверяет, был ли заказ создан сегодня (`test_order_service.py`).\n\n### Пример запроса\n\n```copilot copy\nMy CI is failing on this branch. Can you pull the latest workflow run \nlogs, figure out what is failing, and help me fix it? The relevant files \nare @order.py and @test_order_service.py\n```\n\n### Пример ответа\n\n> \\[!NOTE] Следующий ответ является примером. Ответы Copilot Chat являются недетерминированными, поэтому вы можете получить другой ответ, показанный здесь.\n\nCopilot CLI использует GitHub MCP-сервер для загрузки последнего текущего рабочего процесса, выявления неудачного задания и получения её логов. В нём обнаружена следующая ошибка:\n\n```text\n___ TestOrderService.test_order_created_today ___\n>       assert order[\"created_date\"] == date.today()\nE       AssertionError: assert datetime.date(2024, 1, 15) == datetime.date(2024, 1, 16)\n\ntest_order_service.py:45: AssertionError\n```\n\nПосле прочтения обоих локальных файлов он Copilot CLI замечает, что даты ровно в один день и определяет это **как проблему с границей часового пояса**. CI-runner использует UTC, а ваш локальный компьютер — другой часовой пояс. Когда тест проходит около полуночи, `date.today()` в каждой среде появляются разные даты.\n\nCopilot CLI предлагает стандартизировать вычисления `today` путём внедрения зависимости от часового сигнала или закрепления часового пояса:\n\n```python\nfrom datetime import timezone, datetime\n\ndef get_today():\n    return datetime.now(timezone.utc).date()\n```\n\nИсправление применяется к обоим `order.py` и `test_order_service.py`, обновляя все ссылки для использования нового `get_today()` помощника.\n\nПосле исправления вы можете проверить изменения и провести тесты локально:\n\n1. Беги `/diff` проверить, что Copilot CLI именно изменилось.\n2. Проведите `!pytest test_order_service.py` проверку, чтобы убедиться, что тесты проходят локально.\n3. Нажми на исправление и дай CI перезапуститься.\n\n## Пример сценария 2: Периодические неудачи испытаний в условиях гонки\n\nТест иногда проходит, а иногда проваливается на одной и той же машине. Вам нужно Copilot CLI сравнивать логи прохождения и неудачных забегов, чтобы определить причину.\n\nВ этом примере тестируемый код использует фоновую задачу в `order_service.py` для асинхронного обновления статуса заказа, а тест в `test_order_service.py` утверждает, что итоговый статус — `\"processed\"`.\n\n### Пример запроса для условий гонки\n\n```copilot copy\nThis test passes sometimes and fails sometimes. Can you pull the logs \nfrom the last passing and failing CI runs for test_order_processed \non this branch, compare them, and figure out what is going wrong? \nRelevant files: @order_service.py @test_order_service.py\n```\n\n### Пример реакции для гоночных условий\n\n> \\[!NOTE] Следующий ответ является примером. Ответы Copilot Chat являются недетерминированными, поэтому вы можете получить другой ответ, показанный здесь.\n\nCopilot CLI использует GitHub MCP-сервер для перечисления недавних рабочих процессов на текущей ветке, определяет один проходящий и один неудачный запуск, а также получает логи для обоих. Они сравниваются:\n\n**Пасовый пробег:**\n\n```text\n[DEBUG] Created order #1234\n[DEBUG] Background job started for order #1234\n[DEBUG] Background job completed (52ms)\n[DEBUG] Checking order status\n[DEBUG] Order #1234 status: processed\n```\n\n**Неудачный забег:**\n\n```text\n[DEBUG] Created order #1234\n[DEBUG] Background job started for order #1234\n[DEBUG] Checking order status\n[DEBUG] Order #1234 status: pending\n```\n\nCopilot CLI Обнаруживает, что при проходном запуске фоновая задача выполнена до проверки статуса, а в неудачном запуске статус был проверен, пока работа всё ещё работала. Он определяет это **как гоночное условие** , потому что тест не ждёт завершения фонового задания.\n\nCopilot CLI предлагает добавить явный механизм ожидания перед утверждением и предлагает исправление с помощью помощника по опросу:\n\n```python\nimport time\n\ndef wait_for_status(order_id, expected, timeout=5):\n    start = time.time()\n    while time.time() - start < timeout:\n        order = get_order(order_id)\n        if order.status == expected:\n            return order\n        time.sleep(0.1)\n    raise TimeoutError(\n        f\"Order {order_id} did not reach '{expected}' within {timeout}s\"\n    )\n```\n\n## Дополнительные материалы\n\n* *\n\n[GitHub Copilot CLI](/ru/copilot/how-tos/copilot-cli)"}