Перейти к содержимому

Наполнение проекта из репозитория GitHub

Направьте агента на репозиторий GitHub — и получите готовую доску: каждый issue как история, в том состоянии, которого требует её история изменений, вместе с чек-листами, метками и вехами. Затем тот же агент берёт историю, назначает себя владельцем, проводит её через машину состояний и прикрепляет открытый им pull request.

Эта страница описывает весь цикл. У шага наполнения два пути: GitHub-to-EAT, открытый импортёр East Agile, делает всё одной командой (шаг 3); API импорта делает ту же работу вызов за вызовом (шаги 4 и 5), и именно им управляет агент, когда ему нужен дескриптор задачи. Всё дальнейшее идёт через API, потому что смысл в том, чтобы остальное агент делал без присмотра.

Это не отдельный «ИИ-импорт». Шаг наполнения — тот же импортёр GitHub, который вы запускаете вручную из Настройки проекта → Импорт / Экспорт, описанный в Руководство пользователя → Импорт из других трекеров. Агент вызывает тот же эндпоинт, что и вы. Эта страница добавляет всё, что вокруг: кто держит ключ, как проверить импорт до записи и что агент делает с доской, когда она уже есть.

Источник GitHub на вкладке Import / Export: владелец и репозиторий заполнены, токен пуст, pull request’ы и вехи отмечены

  • Проект — и сессия либо ключ ea_user_…, которым вы его создадите.
  • Ключ агента — ключ ea_agent_…, привязанный к этому проекту. Какая роль ему нужна, зависит от того, какую часть цикла должен вести агент; см. шаг 2. См. также Руководство по API → Два вида ключей.
  • Персональный токен доступа GitHub — с правом чтения issues репозитория. Любой импорт проходит аутентификацию, потому что выборка идёт через GraphQL API GitHub, а GraphQL отклоняет запрос без токена. Опустить его можно только тогда, когда выборку делает Tracker от вашего имени: публичный репозиторий, на развёртывании, у которого есть общий запасной токен (у размещённого eastagiletracker.com он есть; у самостоятельной установки его нет, пока её оператор не задаст GITHUB_IMPORT_PAT), и никогда с --engine direct в GitHub-to-EAT. См. Токены и лимиты запросов.
  • Node.js 22+ — только для пути через GitHub-to-EAT на шаге 3. Пути через API достаточно curl.

Проект должен существовать раньше ключа агента, и создать его должен человек: ключи агентов привязываются к одному проекту при выпуске и сами проект не создают. Сделайте это в интерфейсе или своим ключом ea_user_…:

Окно терминала
curl -X POST https://eastagiletracker.com/api/v1/projects \
-H "X-TrackerToken: $TRACKER_USER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "hello-world", "iteration_length_weeks": 1}'

Ответ несёт project_id, который нужен каждому вызову ниже.

Владелец проекта создаёт ключи агентов в Настройки проекта → Агенты. Выбранная роль решает, какую часть этой страницы агент сделает сам, и разумных ответов два:

  • owner — один ключ проходит весь цикл, включая импорт. Импортировать может только владелец, потому что импорт переписывает форму проекта целиком. Чтобы выпустить агента с ролью owner, вы сами должны быть владельцем проекта: роль агента никогда не превышает роль его создателя.
  • member — минимальные права. Агент берёт истории, двигает их, комментирует и прикрепляет pull request’ы, но импортировать не может. Импорт вы запускаете сами (шаг 5) своим ключом, а затем передаёте доску агенту.

В любом случае не оставляйте значение по умолчанию. Новый ключ агента — viewer, пока вы не скажете иначе, а viewer читает доску, но не берёт и не двигает историю — то есть не делает большую часть этого цикла.

Ключи агентов важны здесь не только из-за доступа. Ключ агента выступает как именованный участник одного проекта, поэтому каждая созданная им история, каждая смена состояния и каждый комментарий приписаны в истории именно этому агенту — отличимы от вашей собственной работы, а не смешаны с ней.

Окно терминала
export TRACKER_TOKEN="ea_agent_xxxxx"

Пусть агент прочитает /meta прежде всего остального:

Окно терминала
curl https://eastagiletracker.com/api/v1/meta \
-H "X-TrackerToken: $TRACKER_TOKEN"

Это отвечает на два вопроса, которые агент иначе угадывал бы: к какому проекту привязан ключ (auth.project_id) и какие переходы состояний законны для каждого типа истории (transitions). Feature идёт unstarted → started → finished → delivered → accepted; chore — только unstarted → started → accepted. Прочитать карту лучше, чем зашить её в код.

GitHub-to-EAT — собственный открытый импортёр East Agile: инструмент командной строки под лицензией MIT, который выполняет весь шаг наполнения — шаги 4 и 5 ниже — одной командой. Берите его, когда за терминалом сидит человек. Берите API под ним, когда управляет агент без присмотра и ему нужен дескриптор задачи для опроса.

Ему нужен Node.js 22+ и нет собственных зависимостей времени выполнения. В npm он пока не опубликован, поэтому установите его из репозитория:

Окно терминала
git clone git@github.com:EastAgile/GitHub-to-EAT.git
cd GitHub-to-EAT
npm install --global .

Затем направьте его на ключ из шага 2 и проект из шага 1:

Окно терминала
export EAT_AGENT_KEY="ea_agent_xxxxx"
github-to-eat --project $PROJECT_ID --repo octocat/hello-world

Сначала он печатает легенду сопоставления — как именно ляжет каждый выбранный тип — и просит подтверждения, прежде чем что-либо записать. Вне терминала, в конвейере, в CI или в агенте показать этот запрос негде, поэтому запуск, который стал бы писать, обязан передать --yes; без него инструмент завершается с кодом 2 и не пишет ничего, вместо того чтобы угадывать ваш ответ. Повторный запуск безопасен: уже импортированное пропускается, а не дублируется.

ФлагЧто делает
--dry-runПредварительная проверка, затем печать плана, который был бы выполнен, — сколько историй он импортировал бы, сколько пропустил бы как уже существующие — и ничего не пишет. --yes не нужен.
--includeКакие типы импортировать, через запятую: issues,prs,milestones,releases,deps. По умолчанию issues, и любой выбор обязан его содержать. Это те же опции, что и в таблице на шаге 6.
--tokenВаш персональный токен доступа GitHub (GITHUB_TOKEN в окружении или в .env тоже считается). Ему нужен repo либо детальное право Issues: Read на этот репозиторий. Обязателен для приватного репозитория, для сервера без общего запасного токена и всегда для --engine direct. Опустите его на движке по умолчанию размещённого сервиса — и Tracker потратит собственный общий бюджет; см. Токены и лимиты запросов.
--engineserver, значение по умолчанию, шлёт один вызов /import/json и оставляет выборку, сопоставление и запись Tracker’у. direct запускает тот же конвейер на вашей машине и пишет через публичный API — то есть читает GitHub сам и всегда требует токен, иначе завершается с кодом 2.
--states, --milestones, --story-type, --no-comments, --no-tasksСужают или переопределяют сопоставление для одного запуска; ничего не сохраняется. Каждый из них подразумевает --engine direct.

Задайте EAT_API_BASE и EAT_APP_BASE, чтобы направить его на самостоятельно размещённый или локальный Tracker; оба по умолчанию указывают на размещённый сервис. README несёт полный справочник флагов, коды выхода и разбор проблем.

Всё ниже — тот же импорт, управляемый вызов за вызовом, и именно это вам нужно, когда его запускает агент.

Импорт доступен только владельцу — используйте ключ агента с ролью owner или собственный ключ, если оставили агента как member. Запустите сначала с dry_run, прежде чем разрешать запись:

Окно терминала
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/import/json \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"source": "github",
"owner": "octocat",
"repo": "hello-world",
"include_pull_requests": true,
"include_milestones": true,
"dry_run": true
}'

Сухой прогон выбирает данные из GitHub, сопоставляет и устраняет дубликаты ровно как настоящий, сообщает те же счётчики — imported, skipped, errors, unmatched — и затем откатывает всю транзакцию. Ничего не сохраняется, и ни одно событие о завершённом импорте не попадает в журнал аудита. Это самый дешёвый способ выяснить, что вы хотели включить вехи или что репозиторий больше, чем вы думали, — пока это ещё ничего не стоит.

Каждый вызов /import/json асинхронный, включая сухой прогон: эндпоинт возвращает 202 с дескриптором задачи, а не результат, и счётчики приходят на задачу, когда вы её опрашиваете (шаг 5). Задача сухого прогона достигает done, как и настоящая; разница в том, что ничего не было записано.

Уберите dry_run и отправьте снова. Как и прежде, эндпоинт возвращает 202 с дескриптором задачи:

{ "import_id": "…", "status": "pending" }

Опрашивайте задачу, пока она не достигнет конечного состояния:

Окно терминала
curl https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/imports/$IMPORT_ID \
-H "X-TrackerToken: $TRACKER_TOKEN"

Статус идёт pending → fetching → writing → done | failed. Конечных только два последних: done несёт счётчики результата, failed несёт сообщение об ошибке и стабильный машинный код, по которому можно ветвиться. Пока выборка идёт постранично, progress_current и progress_total говорят, на какой она странице, — стоит показать, если смотрит человек.

Токены. Передайте "token": "github_pat_…". Опустите его — и сервер подставит общий платформенный токен, который читает только публичные репозитории и расходуется на всех вызывающих в развёртывании; Токены и лимиты запросов объясняет, чего это стоит. Какой бы токен ни использовался, он ведёт вызовы к GitHub и ничего больше: он никогда не попадает в логи, никогда в журнал аудита, никогда не сохраняется и никогда не возвращается в ответе или ошибке.

Повторный запуск безопасен. Строка, уже импортированная ранее, опознаётся по id в источнике и пропускается, а не дублируется. Второй импорт дополняет доску тем, что появилось после первого.

Issues импортируются по умолчанию. Всё остальное подключается по выбору, по одному флагу на тип:

Из GitHubСтановитсяФлаг
IssueИстория. Открытая → unstarted в Backlog. Закрытая → accepted, либо rejected, когда GitHub сообщает, что issue закрыт как not_planned или duplicate (история тогда несёт соответствующую метку).по умолчанию
Чек-лист в теле issueЗадачи — каждая строка - [ ] / - [x] становится одной задачей в порядке текста, [x] приходит уже выполненной. Чек-лист остаётся и в описании.по умолчанию
МеткиМетки, перенесённые как есть.по умолчанию
Pull requestИстория с меткой pull-request. Открыт → started, влит → accepted, закрыт без влития → rejected.include_pull_requests
ВехаЭпик, названный по вехе и лишённый дублей по заголовку — два issue с общей вехой попадают в один эпик. С выключенным флагом она едет как метка milestone:<заголовок>.include_milestones
РелизИстория релиза. Опубликован → accepted, черновик → unstarted.include_releases
Зависимость issueБлокер на истории. Только issues, никогда pull request’ы.include_dependencies

Тип истории выводится, когда issue его не называет. Метка, содержащая bug, fix или defect, — либо заголовок, начинающийся с fix или bug, — делает её багом; chore, maintenance, devops или infra делают её chore; всё остальное — feature. Об этом стоит знать до импорта, потому что в East Agile Tracker points несут только features и только features питают velocity. См. Введение → Истории.

Доска проекта сразу после импорта демонстрационного репозитория: issues стали историями с метками, вехи — эпиками, люди из GitHub — владельцами

Теперь у доски есть история изменений, а у агента — ключ. Дальше цикл укладывается в четыре вызова.

Найдите историю или напишите её. Отфильтруйте доску, чтобы найти, что взять:

Окно терминала
curl "https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories?state=unstarted" \
-H "X-TrackerToken: $TRACKER_TOKEN"

import_source=github сужает выборку до того, что принёс импорт. Если агент нашёл работу, которую репозиторий никогда не фиксировал, он создаёт историю сам — см. Руководство по API → Создание истории.

Возьмите её себе. Агент добавляет себя владельцем, отправив пустое тело:

Окно терминала
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/owners \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'

Пустое тело означает вызывающего, поэтому агенту не нужно знать собственный id. Доска теперь показывает агента владельцем, и по этому наблюдающий человек понимает, что работа занята.

Начните её.

Окно терминала
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/transitions \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"to": "started"}'

Дальше агент идёт и делает работу — читает репозиторий, пишет код, открывает pull request. Эта часть происходит в вашем инструменте разработки, не здесь.

Прикрепите pull request.

Окно терминала
curl -X POST https://eastagiletracker.com/api/v1/projects/$PROJECT_ID/stories/$STORY_ID/links \
-H "X-TrackerToken: $TRACKER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"url": "https://github.com/octocat/hello-world/pull/42"}'

URL pull request’а на GitHub распознаётся сам — говорить об этом не нужно. История и закрывающий её код теперь в одном клике друг от друга, в обе стороны.

Завершите её. Переведите в finished и остановитесь. У feature впереди ещё delivered и accepted, и это ворота проверки: что работа сделана верно, решает кто-то, кроме агента. У chore таких ворот нет — started → accepted и есть весь её оставшийся путь.

Импортированный закрытый issue: в разделе CODE ссылка на исправивший его pull request, рядом комментарии из GitHub

Любой импорт проходит аутентификацию. Выборка issues, комментариев и pull request’ов идёт через GraphQL API GitHub, а GraphQL отклоняет запрос без токена — анонимного уровня нет ни для публичного репозитория, ни для приватного. Вопрос не в том, дойдёт ли токен до GitHub, а только чей.

Передайте token в вызове импорта или --token в GitHub-to-EAT. Достаточно детального персонального токена доступа с правом чтения issues репозитория. Он ведёт вызовы к GitHub и ничего больше: никогда не попадает в логи, никогда в журнал аудита, никогда не сохраняется и никогда не возвращается в ответе или ошибке.

Для всего серьёзнее демонстрации приносите свой. Тогда вы тратите бюджет, которого никто больше не касается, и никакая предварительная проверка не откажет вам из-за чужого импорта.

--engine direct не оставляет выбора. Этот движок читает GitHub с вашей машины, а не через Tracker, поэтому токен сервера недоступен; запуск без токена завершается с кодом 2 и ошибкой использования до того, как что-либо выберет или запишет. GITHUB_TOKEN в вашем окружении или в .env считается так же, как --token.

Токен требует обход issues, а не весь движок. direct читает issues, комментарии и pull request’ы через GraphQL, у которого нет анонимного режима; REST он трогает только ради списка releases и бесплатной пробы /rate_limit. Инструмент до сих пор поставляет более старый анонимный REST-загрузчик, который проводил импорт публичного репозитория в рамках лимита 60 в час, но ни один путь CLI до него уже не доходит и его собираются удалить — поэтому считайте --token обязательным для direct.

Не отправляйте token — и сервер подставит платформенный токен, настроенный его оператором (GITHUB_IMPORT_PAT). С ним идут три ограничения:

  • Это необязательная настройка. Размещённый eastagiletracker.com предоставляет такой токен, поэтому импорт публичного репозитория без токена там работает. У самостоятельной установки — скачанного бинарника — его нет, пока её оператор не задаст GITHUB_IMPORT_PAT в окружении, и до тех пор она отклоняет каждый импорт без токена ошибкой 400 import_github_no_token.
  • Он читает только публичные репозитории. Размещённый сервис выпускает его только на чтение публичных репозиториев, поэтому приватному репозиторию всегда нужен ваш собственный токен.
  • Все вызывающие в развёртывании делят один бюджет. Прежде чем запустить импорт без токена, сервер читает остаток очков GraphQL общего токена и отклоняет запрос с 400 import_github_shared_quota_low ниже 500. Бюджет, кончившийся посреди импорта, роняет задачу с import_github_rate_limited_platform. Оба сообщения называют одно и то же решение: дать свой токен.

GitHub считает свои два API раздельно, и потолок без аутентификации на два порядка ниже.

API GitHubИспользуется дляС токеномБез токена
GraphQLIssues, комментарии, pull request’ы, вложенные issues, зависимости5000 очков в час, начисляемых по узлам, которые возвращает запросОтказ — у GraphQL нет анонимного уровня
RESTРелизы (include_releases) и предварительная проверка /rate_limit5000 запросов в час60 запросов в час, считаемых на IP-адрес и делимых со всеми за ним

Импорт никогда не скатывается на этот уровень в 60 в час: раз отправлять нечего, запрос отклоняется заранее, а не повторяется анонимно. Число важно для того, что вы делаете вокруг импорта — скрипт, читающий GitHub напрямую, или оболочка в одной сети с другими клиентами исчерпывает 60 запросов за секунды.

Читайте остаток бюджета когда угодно; GET /rate_limit освобождён от обоих лимитов, поэтому проверка ничего не стоит:

Окно терминала
curl -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/rate_limit

Очки GraphQL — не запросы. GitHub оценивает запрос по узлам, которые он возвращает, поэтому одна страница из 100 issues вместе с их комментариями и назначенными стоит много очков, а большой репозиторий тратит часовой бюджет за куда меньшее число вызовов, чем подсказывают цифры эпохи REST. --dry-run (шаг 3) и dry_run (шаг 4) стоят каждый столько же очков, сколько настоящая выборка — именно это делает их счётчики надёжными — поэтому закладывайте два прохода, когда готовите большой импорт.

  • Руководство по API — грамматика поиска, поток событий, массовые переходы, идемпотентные записи и остальная поверхность.
  • Руководство пользователя — те же операции из интерфейса и остальные десять импортёров.
  • Введение — почему машина состояний и четыре типа историй устроены именно так.
  • GitHub-to-EAT — собственный репозиторий импортёра: каждый флаг, оба движка и как в него внести вклад.