- SourceCraftClient (httpx): list_runs, get_run, get_cube_logs (постранично), run_commit_sha; ретраи на сетевые ошибки и 5xx с экспоненциальной задержкой, 4xx — SourceCraftError без повторов - модели: RunStatus/EventType из swagger, «1970-01-01» = не задано, failed_cubes без служебных #-кубов - у прогона в API нет sha → куб check/meta в tgit-uploads печатает TGIT_COMMIT_SHA (ADR-014) - CLI: python -m app.sourcecraft.cli runs - тесты на реальных ответах API (фикстуры), порог покрытия 45 → 80 Refs #10 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
7.1 KiB
Markdown
114 lines
7.1 KiB
Markdown
# SourceCraft API — шпаргалка
|
||
|
||
> Issues и PR ведём в Gitea ([`GITEA_API.md`](GITEA_API.md), ADR-010). Здесь нужны в основном CI-прогоны, логи и секреты;
|
||
> разделы про issues/метки/PR — справочно (бот и скрипты могут работать с `tgit-uploads`).
|
||
|
||
Справочник: [методы](https://sourcecraft.dev/portal/docs/en/api-ref/index.md) ·
|
||
[интерактивный](https://api.sourcecraft.tech/docs/index.html) ·
|
||
[swagger.json](https://api.sourcecraft.tech/sourcecraft.swagger.json)
|
||
|
||
```bash
|
||
set -a; . ./.env; set +a # SOURCECRAFT_TOKEN
|
||
R=https://api.sourcecraft.tech/repos/rogachevegorushka/tgit
|
||
H="Authorization: Bearer $SOURCECRAFT_TOKEN"
|
||
alias curl='curl --retry 4 --retry-all-errors --retry-delay 2'
|
||
J="Content-Type: application/json"
|
||
```
|
||
|
||
> В CI вместо личного токена — предопределённая переменная `SOURCECRAFT_TOKEN`.
|
||
|
||
## Подводные камни
|
||
|
||
- Соединение с `api.sourcecraft.tech` иногда рвётся (`curl: (35)`, пустой ответ) — отсюда `--retry`. Перед повторным POST проверить, не создалась ли сущность.
|
||
- `color` у метки — hex **без** `#` (`"ff7f0e"`), иначе `400 ValidationError`.
|
||
- Ответы-списки кладут элементы в разные ключи: `/issues` → `issues`, `/labels` и `/milestones` → `items`, `/pulls` → `pull_requests`, метки issue → `labels`, связи → `links`.
|
||
- Веха в issue задаётся `milestone_id` (UUID); `milestone_slug` отвергается с `400 must be a valid ID`.
|
||
- Issue адресуется номером (`issues/1`), метка — slug'ом (`size/0.5` → `size-0-5`).
|
||
- Тело issue — поле `description` (не `body`); тело комментария — `body`.
|
||
- Длинный markdown удобнее собрать в JSON-файл и передать `--data @file.json`.
|
||
|
||
## Issues
|
||
|
||
```bash
|
||
# список / одна
|
||
curl -s -H "$H" "$R/issues"
|
||
curl -s -H "$H" "$R/issues/1"
|
||
|
||
# создать (status_slug: open | inProgress | paused | closed | declined | duplicate)
|
||
curl -s -X POST -H "$H" -H "$J" "$R/issues" --data @issue.json
|
||
# issue.json: {"title": "...", "description": "...", "label_slugs": ["bot","feature","size-1"], "status_slug": "open"}
|
||
|
||
# обновить (описание, статус, исполнитель)
|
||
curl -s -X PATCH -H "$H" -H "$J" "$R/issues/1" -d '{"status_slug":"closed"}'
|
||
|
||
# комментарий
|
||
curl -s -X POST -H "$H" -H "$J" "$R/issues/1/comments" -d '{"body":"текст"}'
|
||
|
||
# метки issue: POST — добавить, PUT — заменить, DELETE — убрать
|
||
curl -s -X POST -H "$H" -H "$J" "$R/issues/1/labels" -d '{"slugs":["ci"]}'
|
||
|
||
# связь между issue (related_to | parent_of | subissue_of | blocks | blocked_by | duplicates | duplicated_by)
|
||
curl -s -X POST -H "$H" -H "$J" "$R/issues/9/issue_links" -d '{"target_issue_slug":"8","link_type":"blocked_by"}'
|
||
```
|
||
|
||
## Вехи
|
||
|
||
```bash
|
||
curl -s -H "$H" "$R/milestones"
|
||
curl -s -X POST -H "$H" -H "$J" "$R/milestones" -d '{"name":"M5 · …","description":"…"}' # → id для milestone_id
|
||
```
|
||
|
||
## CI/CD
|
||
|
||
```bash
|
||
curl -s -H "$H" "$R/cicd/runs" # прогоны: {"runs": [...], "next_page_token"}
|
||
curl -s -H "$H" "$R/cicd/runs/<run>" # прогон: status + workflows[].tasks[].cubes[]
|
||
curl -s -H "$H" "$R/cicd/logs/<run>/<workflow>/<task>/<cube>" # лог куба: {"logs": "...", "page_complete", "done"}
|
||
|
||
# ручной запуск (head и config_revision — {"branch"|"tag"|"commit": ...}; по умолчанию — основная ветка)
|
||
curl -s -X POST -H "$H" -H "$J" "$R/cicd/runs" \
|
||
-d '{"head":{"branch":"feat/x"},"config_revision":{"branch":"feat/x"},"workflows":[{"name":"check"}]}'
|
||
|
||
# секрет: value — base64 от значения
|
||
curl -s -X PUT -H "$H" -H "$J" "$R/secrets/DEPLOY_HOST" -d "{\"value\":\"$(printf %s 'user@host' | base64 -w0)\"}"
|
||
```
|
||
|
||
- **Триггеры `on:` читаются из `.sourcecraft/ci.yaml` основной ветки репозитория.** Пока файла там нет — push ничего
|
||
не запускает. Основная ветка `tgit` в SourceCraft — `dev` (`PATCH $R -d '{"default_branch":"dev"}'`), чтобы CI
|
||
включался мержем в `dev`, а не продвижением в `main`.
|
||
- Прогон: `slug` — числовой (`1000000`…), `status`: `created` → `processing` → `success`/`failed`; `event_type`:
|
||
`push`/`manual`/…. У кубов служебные шаги со `slug`, начинающимся на `#` (`#git-clone`, `#prepare-image-for-<cube>`).
|
||
- Если куб упал, остальные кубы задачи остаются в `created` и не запускаются.
|
||
- **В прогоне нет sha коммита** (ни в списке, ни в деталях), фильтра по коммиту нет → в `tgit-uploads` куб `check/meta` печатает `TGIT_COMMIT_SHA=…`, бот читает его лог (ADR-014).
|
||
- Логи служебных кубов (`#git-clone` и т.п.) API не отдаёт: `400 CITaskName.Pattern`.
|
||
- Логи постранично: `?page=N` с 1; читать по порядку, пока `page_complete: true`; следующая страница незаконченной — 404.
|
||
- Статусы прогона: `created`, `prepared`, `processing`, `success`, `failed`, `canceled`, `timeout`, `skipped`, `awaiting_approval`, `rejected`. Типы события: `push`, `pr_update`, `manual`, `restart`, `schedule`, `repository_event`.
|
||
- Очередь бесплатных раннеров бывает минутами: прогон может стоять в `prepared`/`created` до ~6 мин до старта.
|
||
- Веб-интерфейс — SPA, на любой путь отвечает 200: формат ссылки на прогон снаружи не проверить (`SOURCECRAFT_RUN_URL_TEMPLATE`).
|
||
- Код в кубе склонирован в `/sourcecraft/workspace` (`$SOURCECRAFT_WORKSPACE`) — это рабочий каталог. Переменные:
|
||
`SOURCECRAFT_COMMIT_SHA`, `SOURCECRAFT_COMMIT_REF_NAME` и др.
|
||
- Исходящих webhooks нет — статус CI получаем опросом (ADR-003).
|
||
|
||
## Метки репозитория
|
||
|
||
```bash
|
||
curl -s -H "$H" "$R/labels"
|
||
curl -s -X POST -H "$H" -H "$J" "$R/labels" -d '{"name":"size/1","slug":"size-1","color":"a0a0a0"}'
|
||
```
|
||
|
||
Заведены: зоны `bot` `ci` `infra` `llm` `docs` · типы `feature` `fix` `refactor` · размеры `size/0.5` `size/1` `size/2`.
|
||
|
||
## Pull requests
|
||
|
||
```bash
|
||
# создать PR в dev
|
||
curl -s -X POST -H "$H" -H "$J" "$R/pulls" --data @pr.json
|
||
# pr.json: {"title": "...", "description": "...", "source_branch": "feat/2-x", "target_branch": "dev", "publish": true}
|
||
|
||
curl -s -H "$H" "$R/pulls/1"
|
||
curl -s -H "$H" "$R/pulls/1/merge-checks"
|
||
|
||
# мерж (rebase | squash, delete_branch)
|
||
curl -s -X POST -H "$H" -H "$J" "$R/pulls/1/merge" -d '{"delete_branch": true}'
|
||
```
|