Проверьте GitHub-репозиторий до его внедрения
Анализ GitHub-репозиториев через git clone: release notes, changelog, структура, code review, сравнение версий, статистика контрибьюторов.
Как агент работает
Глубина разбора задаётся целью: оценка библиотеки перед зависимостью требует 12–24 месяцев истории плюс issue и релизы, приёмка работы подрядчика — периода договора, поиск причины регрессии — истории до последней рабочей версии, а «что это вообще такое» обходится одним коммитом. Клон по умолчанию приходит с глубиной 1: счётчик коммитов даёт единицу, тегов ноль, а в авторах ровно один человек.
То, чего в истории нет, берётся из публичного REST GitHub: состояние archived, license.spdx_id, размер репозитория, дата последнего пуша, tag_name и published_at последнего релиза, закрытые issue со временем закрытия и метками. Поле open_issues_count включает открытые pull request и завышает число багов, а лимит без токена — 60 запросов в час и 10 в минуту к поиску, отсюда 5–8 на репозиторий.
Техника чтения истории отсекает тихо ложные числа. Подсчёт объёма идёт без merge-коммитов, лента релизов — по первому родителю, авторы склеиваются по e-mail до подсчёта, иначе один человек с тремя адресами удваивает bus factor. Churn считается с исключением lock-файлов, миграций и сгенерированного: один файл схемы легко даёт плюс-минус сорок пять тысяч строк и забивает метрику.
Вердикт о живости формулируется числами: archived значит закрытый проект, коммит свежее 90 дней — активный, тишина больше 12 месяцев — заброшенный, а лаг между релизом и последним коммитом свыше 180 дней означает, что фиксы живут только в основной ветке. Bus factor — минимальное число авторов, дающих половину коммитов за год; лицензии MIT, BSD и Apache-2.0 идут в закрытый продукт, AGPL — нет.
Границы разбора названы прямо: по числу строк качество кода не оценивается, строки не переводятся в часы и рубли, расхождение заявленного с найденным — вопрос подрядчику, а не обвинение. Категоризация по Conventional Commits ниже 60% применимости недостоверна и так и пишется в отчёте, а bisect на обрезанной истории упрётся в границу и назовёт виновником самый старый коммит.
1. Цель определяет глубину
| Цель | История | GitHub API | Что решается |
|---|---|---|---|
| Оценка библиотеки перед зависимостью | 12–24 мес | issues, releases | Брать / не брать / форкнуть |
| Приёмка работы подрядчика | период договора | нет | Подписывать ли акт |
| Что изменилось между версиями | диапазон тегов | releases | Обновляться ли |
| Причина регрессии | до рабочей версии | нет | Какой коммит виноват |
| Release notes | период отчёта | PR-заголовки | Текст для пользователей |
| Структура и технологии | 1 коммит | нет | Что это вообще такое |
Только последней строке хватает клона по умолчанию, остальным нужен добор истории.
2. Клонирование: shell
2.1. Клон приходит обрезанным
--depth=1 отдаёт обрезанный клон: после него git rev-list --count HEAD даёт 1, git tag — 0, shortlog — одного автора. Статистика на таком клоне уверенная и полностью ложная. Первая команда после клона:
true — добирай. Три рецепта:
Первый — вся история, годится до ~200 МБ (поле size из API). Второй быстрее, но --depth=N считает по каждой ветви слияния отдельно (--depth=300 дал 642 коммита) — количество из глубины не выводится. Третий — единственный способ взять календарный период, и требует явного refspec (origin main): без имени ветки HEAD останется на одном коммите. --tags добирай всегда — без тегов нет ни сравнения версий, ни лага релизов.
2.2. Правки и PR
Предложения по итогам — ветка через git checkout -b coworker/session-<id> в sandbox_bash, правки edit_file, коммит и PR — кнопки владельца в панели ревью (сама определит GitHub/GitLab и вернёт номер со ссылкой). Пушить из sandbox_bash бессмысленно — токена в дереве нет.
3. Что берётся из API, а не из git
Issue, отзывчивость мейнтейнеров и релизы история не знает. web_fetch по REST GitHub, база https://api.github.com (проверено 2026-07-28):
/repos/{owner}/{repo}—pushed_at,archived,license.spdx_id,open_issues_count,forks_count,subscribers_count,size,default_branch;/repos/{owner}/{repo}/releases/latest—tag_name,published_at;/repos/{owner}/{repo}/issues?state=closed&sort=updated&per_page=100—created_at,closed_at,comments, метки;/search/issues?q=repo:{owner}/{repo}+is:issue+is:open—total_count(сis:pr— открытые PR).
Две ловушки. open_issues_count включает PR: у psf/requests на 2026-07-28 поле показывало 233 при 146 issue и 87 PR — «233 открытых бага» завышает на 60%; считай раздельно через search. Лимит без токена: 60 запросов/час на IP, 10/мин к search — 5–8 запросов на репозиторий, без сплошной пагинации.
4. Техника чтения истории
- Поиск по содержимому:
-S'строка'— изменилось число вхождений;-G'regex'— строка попала в diff. Вопрос «когда появилось/исчезло»:git log -S'DEFAULT_TIMEOUT' --format='%h %ad %an %s' --date=short --no-merges. - Переименования:
--follow -- path/to/file(один путь, не дружит с--name-only); без него «файл создан 3 месяца назад» — ложь. - Один автор ≠ одна строка:
Lev KokovkinиKokovkin Levс одним e-mail, один человек — три github-noreply адреса. Сначалаgit log --format='%an <%ae>' | sort -uи склейка по почте, иначе bus factor завышен вдвое. - Объём правок:
--numstat. Генерация, миграции и лок-файлы забивают метрику (schemas.generated.json+45 481 −45 481); исключай:-- . ':(exclude)*.lock' ':(exclude)*generated*' ':(exclude)*/migrations/*'.
5. Живой проект или заброшенный
По убыванию надёжности:
archived: true— проект закрыт, дальше только форк.- Последний коммит в основную ветку: до 90 дней — активен, 90–365 — дремлет, больше 12 месяцев без коммитов и ответов в issue — заброшен.
- Лаг релиза — дней между
published_atпоследнего релиза и последним коммитом. 74 дня (requests, 2026-07-28) — норма зрелой библиотеки; больше 180 при живых коммитах — фиксы только в основной ветке, ставить придётся по git-ссылке, которую внутренние прокси часто не пропускают. - Авторов с коммитом за 12 месяцев: один — держится на человеке, двое-трое — обычная библиотека, десять+ — сообщество.
- Ритм по помесячной гистограмме: ровная линия — живая разработка, всплеск год назад и тишина — выложено и брошено.
Вердикт числами: «за 12 месяцев 1 234 коммита от 8 авторов, последний 2026-07-27, релиз отстаёт на 74 дня».
6. Отзывчивость мейнтейнеров
Скорость закрытия сама по себе ничего не значит: stale-бот даёт отличную медиану на мёртвом проекте. По последним 100 закрытым issue: медиана closed_at − created_at; доля comments == 0 (больше 30% — вопросы не читают); доля stale/wontfix (выше доли фиксов — уборка, не поддержка); медиана времени до первого ответа мейнтейнера — её почувствует пришедший с багом.
Вердикт: «медиана закрытия 12 дней, но 41 из 100 закрыты без ответа и 18 stale — на ваш баг, скорее всего, не ответят».
7. Bus factor
Минимальное число авторов, дающих 50% коммитов за 12 месяцев (после склейки дублей):
Ответ — номер первой строки с накопленной долей > 50%. Bus factor 1 (первый автор 73,4% при восьми) — обычная картина, показывай её. Порог: bus factor 1 в критичном пути (платежи, обмен с 1С, выгрузка на маркетплейс) — закладывай стоимость форка; у утилиты форматирования дат — приемлемо.
8. Лицензия
license.spdx_id из API + сверка с файлом LICENSE: детектор ошибается на правленых текстах, NOASSERTION = «не распознано» = все права у автора.
- MIT, BSD, Apache-2.0 — можно в закрытый продукт; Apache-2.0 даёт патентную лицензию и требует NOTICE.
- GPL-2.0/3.0 — производное на тех же условиях: для SaaS чаще терпимо, для коробки/десктопа/мобильного — нет.
- AGPL-3.0 — срабатывает и при доступе по сети: для SaaS означает открыть код.
- Нет файла лицензии — не «свободно», а запрет: использование без письменного разрешения неправомерно.
- Смена лицензии —
git log --oneline --follow -- LICENSE; переезд с MIT на BSL оставляет старые версии под старой лицензией — иногда единственный законный путь.
9. Безопасность, видимая из репозитория
Секреты в истории. Удалённый из дерева секрет остаётся в объектах навсегда; git grep смотрит только текущий срез. Две плоскости:
Отсеки .env.example и публичные сертификаты (пять попаданий из семи на реальном репозитории). Найденный ключ скомпрометирован независимо от удаления: отозвать и перевыпустить, а не «вычистить историю».
Устаревшие зависимости. Объявленные версии из package.json / requirements.txt / pyproject.toml против актуальных через web_fetch (https://pypi.org/pypi/{name}/json, https://registry.npmjs.org/{name}). Отчитывайся отставанием: «7 из 34 отстают больше чем на 2 мажорные версии» — оценка стоимости обновления.
Гигиена процесса. .github/workflows с тестами, SECURITY.md, dependabot.yml. Нет CI при двух десятках контрибьюторов — в основной ветке регулярно сломанное состояние.
10. Категоризация коммитов и её предел
Conventional Commits с падением на ключевые слова, включая русские:
Сначала измерь применимость — долю сообщений под ^[a-z]+(\([^)]*\))?!?: . Ниже 60% — категоризация недостоверна, и это пишут в отчёте. Даже при 89% соблюдения 49% коммитов может уйти в «Прочее» (релизные feat:, склеившие десятки изменений). Правило: проценты по категориям — вспомогательная цифра; вывод делается чтением заголовков. Больше трети в «Прочем» — пиши: категоризация не работает, разбор сделан вручную по N коммитам.
11. Сравнение версий и поиск регрессии
Для обновления по порядку: изменился ли публичный API (!:, BREAKING CHANGE, диффы файлов экспорта), появились ли обязательные настройки (конфиги, .env.example), выросли ли минимальные требования (python_requires, engines, go). Остальное — детали реализации.
Регрессия: сузь диапазон тегами («работало на 1.4.0, сломалось на 1.5.0») → -S по имени функции или тексту ошибки → --follow по файлу. git bisect — только при воспроизводимой проверке и неурезанной истории: на shallow-клоне он назовёт виновником самый старый доступный коммит.
12. Приёмка работы подрядчика
Цифры пойдут в разговор о деньгах, порядок жёсткий: границы (период договора и ветки, git branch -a --sort=-committerdate) → авторы подрядчика со склеенными дублями → объём без сгенерированного (сгенерированный клиент API даёт 60 тысяч строк одним коммитом) → состав работы по разделу 10 плюс чтение заголовков → процесс: распределение по датам (равномерно или всё за два дня до сдачи), часы (--date=format:'%H'), появились ли тесты, зелёный ли CI.
Нельзя превращать строки в часы и рубли: рефакторинг на −2 000 строк может стоить дороже добавленных 10 000. Историю сопоставляй с почасовой ставкой как проверку правдоподобия, не как расчёт суммы. Расхождение заявленного и наблюдаемого — вопрос подрядчику, а не обвинение.
13. Шаблоны отчётов
Оценка библиотеки перед зависимостью
Release notes — только заметное пользователю: заголовок с периодом, абзац «коротко», «Новые возможности» (что теперь может пользователь), «Исправления» (что перестало ломаться и у кого проявлялось), «Важно при обновлении» (ломающее и что делать), в конце «Внутренние изменения: N коммитов» и счётчики. Каждый пункт — с 7-символьным хешем.
Приёмка — таблица «заявлено / найдено в истории / вывод» по пунктам ТЗ, ниже объём без сгенерированного, даты, замечания. Регрессия — подозреваемый коммит, диапазон, чем подтверждено, обратимо ли откатом.
14. Как переводить коммиты
Читатель — чаще владелец бизнеса, а не разработчик.
15. Режимы отказа
- Пять источников тихо неверных чисел: обрезанный клон (1 коммит, 0 тегов),
shortlogбезHEAD(пустой вывод при непустомgit log), несклеенные авторы, churn по сгенерированным файлам,open_issues_countкак число багов. - Качество кода по числу строк не оценивается — из истории видно поведение команды, не качество.
- Ответ по README — README это намерение, история — реальность; расхождение само по себе находка: «README обещает поддержку версии X, в коде она удалена в {hash} восемь месяцев назад».
Похожие навыки
Попробуйте этот навык
Зарегистрируйтесь и используйте навык «GitHub Repo Analyzer» бесплатно.