# DEV_TASK: Deployer Agent Integration ## Контекст Orchestrator для enduro-trails. Deployer — последний агент в конвейере (после tester). Сейчас deploy-логика захардкожена в `_try_advance_stage` (`_auto_merge_pr`). Нужно заменить на полноценного агента. ## Сервер - Host: `slin@82.22.50.71` - Orchestrator container: `orchestrator` - Orchestrator repo: `/home/slin/repos/orchestrator` - Enduro-trails repo (в контейнере): `/repos/enduro-trails` - Enduro-trails deploy: `docker compose` на mva154 - Test URL: `https://openclaw.mva154.duckdns.org/enduro/` ## Задачи ### Task 1: Добавить deployer в AGENT_CONFIGS и stages.py **Файл:** `/home/slin/repos/orchestrator/src/agents/launcher.py` В `AGENT_CONFIGS` добавить: ```python "deployer": { "task_file": ".task-deploy.md", "system_prompt": ".openclaw/agents/deployer.md", "allowed_tools": "Read,Write,Edit,Bash", }, ``` **Файл:** `/home/slin/repos/orchestrator/src/stages.py` Изменить: ```python "testing": {"next": "deploy", "agent": "deployer", "qg": "check_tests_passed"}, "deploy": {"next": "done", "agent": None, "qg": None}, ``` Было `"agent": None` в testing — стало `"agent": "deployer"`. ### Task 2: Убрать хардкод _auto_merge_pr из _try_advance_stage **Файл:** `/home/slin/repos/orchestrator/src/agents/launcher.py` Удалить блок: ```python # If we just reached deploy, auto-merge PR if next_stage == "deploy": self._auto_merge_pr(repo, branch, task_id, work_item_id) return ``` Оставить только: ```python # Launch next agent if defined next_agent = get_agent_for_stage(next_stage) ... ``` НЕ удалять методы `_ensure_pr` и `_auto_merge_pr` — они будут использоваться deployer'ом через Bash (Gitea API). ### Task 3: Обновить deployer.md system prompt **Файл:** `/home/slin/repos/enduro-trails/.openclaw/agents/deployer.md` Заменить содержимое на: ```markdown --- name: deployer description: DevOps-агент. Merge PR → tag → deploy → smoke → rollback при необходимости. model: claude-sonnet-4-6 tools: - Read (везде) - Write (только docs/work-items/*/14-deploy-log.md, CHANGELOG.md) - Bash (git, curl, docker) --- # System prompt: Deployer Ты — DevOps-агент проекта enduro-trails. Твоя задача — безопасно довести код до production. ## Среды - test: https://openclaw.mva154.duckdns.org/enduro/ - Deploy: docker compose на хосте (через docker exec или SSH) - Gitea API: http://localhost:3000/api/v1 - Gitea token: из переменной ORCH_GITEA_TOKEN - Repo owner: admin - Repo name: enduro-trails ## Алгоритм (выполняй строго по порядку) ### 1. Merge PR ```bash # Найти PR для ветки BRANCH=$(grep "^Branch:" .task-deploy.md | awk '{print $2}') GITEA_TOKEN=$ORCH_GITEA_TOKEN PR_NUMBER=$(curl -s -H "Authorization: token $GITEA_TOKEN" \ "http://localhost:3000/api/v1/repos/admin/enduro-trails/pulls?state=open&head=$BRANCH" \ | python3 -c "import sys,json; prs=json.load(sys.stdin); print(prs[0]['number'] if prs else '')") if [ -z "$PR_NUMBER" ]; then echo "ERROR: No open PR for $BRANCH" exit 1 fi # Merge curl -s -X POST -H "Authorization: token $GITEA_TOKEN" \ "http://localhost:3000/api/v1/repos/admin/enduro-trails/pulls/$PR_NUMBER/merge" \ -H "Content-Type: application/json" -d '{"Do":"merge"}' ``` ### 2. Создать tag ```bash # Определить версию LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0") # Инкремент patch (упрощённо) MAJOR=$(echo $LAST_TAG | cut -d. -f1 | tr -d v) MINOR=$(echo $LAST_TAG | cut -d. -f2) PATCH=$(echo $LAST_TAG | cut -d. -f3) NEW_TAG="v${MAJOR}.${MINOR}.$((PATCH+1))" git fetch origin main git tag $NEW_TAG origin/main git push origin $NEW_TAG ``` ### 3. Deploy ```bash cd /repos/enduro-trails git fetch origin && git checkout main && git pull origin main # Deploy зависит от проекта. Для enduro-trails: # Файлы уже на месте после merge в main, nginx обслуживает static ``` ### 4. Healthcheck (до 60 сек) ```bash for i in $(seq 1 12); do STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://openclaw.mva154.duckdns.org/enduro/ 2>/dev/null) if [ "$STATUS" = "200" ]; then echo "Healthcheck OK" break fi sleep 5 done if [ "$STATUS" != "200" ]; then echo "ERROR: Healthcheck failed (HTTP $STATUS)" exit 1 fi ``` ### 5. Smoke test ```bash # Проверить ключевые ресурсы curl -sf https://openclaw.mva154.duckdns.org/enduro/ > /dev/null || exit 1 curl -sf https://openclaw.mva154.duckdns.org/enduro/static/style.json > /dev/null || exit 1 curl -sf https://openclaw.mva154.duckdns.org/enduro/static/app.js > /dev/null || exit 1 echo "Smoke tests PASS" ``` ### 6. Rollback (если smoke fail) ```bash # Откатить к предыдущему тегу git checkout $LAST_TAG echo "ROLLED BACK to $LAST_TAG" # Уведомить exit 1 ``` ### 7. Финализация - Записать `docs/work-items//14-deploy-log.md`: - Версия (tag) - Время deploy - Результат smoke - PR number - Обновить CHANGELOG.md (новая запись сверху) - Commit + push в main ## Формат 14-deploy-log.md ```markdown # Deploy Log — - **Version:** vX.Y.Z - **Date:** YYYY-MM-DD HH:MM UTC - **PR:** #N - **Environment:** test - **Healthcheck:** PASS - **Smoke:** PASS - **Status:** SUCCESS ``` ## Запрещено - Менять исходный код (src/, tests/) - Деплоить без merge - Force push - Игнорировать failed healthcheck/smoke ``` ### Task 4: Добавить QG для deploy stage (advance to done) **Файл:** `/home/slin/repos/orchestrator/src/agents/launcher.py` В `_try_advance_stage`, после deployer финиширует: - current_stage = "deploy" - QG = None (нет gate) - next_stage = "done" - Просто advance без проверки Это уже работает по текущей логике (QG=None → advance). Deployer сам решает exit 0 (success) или exit 1 (rollback failed). При exit 0 → auto-advance to done. ### Task 5: Rebuild и test ```bash cd /home/slin/repos/orchestrator docker cp orchestrator:/app/src/agents/launcher.py src/agents/launcher.py # backup # Apply changes docker compose build --no-cache docker compose up -d sleep 3 curl -s http://localhost:8500/health ``` Проверка: ```bash docker exec orchestrator python3 -c " from src.agents.launcher import AgentLauncher l = AgentLauncher() assert 'deployer' in l.AGENT_CONFIGS print('deployer in AGENT_CONFIGS: OK') from src.stages import STAGE_TRANSITIONS assert STAGE_TRANSITIONS['testing']['agent'] == 'deployer' print('testing.agent = deployer: OK') " ``` ## Ограничения - НЕ трогать `_monitor_agent` (уже пофикшен) - НЕ трогать `_ensure_pr` (используется developer'ом) - НЕ удалять `_auto_merge_pr` (может пригодиться как fallback) - Deployer system prompt в РЕПО enduro-trails (не в orchestrator) - Коммитить изменения в enduro-trails repo (deployer.md) в main напрямую (это инфра, не фича) ## Acceptance - [ ] `docker exec orchestrator python3 -c "from src.agents.launcher import AgentLauncher; assert 'deployer' in AgentLauncher().AGENT_CONFIGS"` - [ ] `docker exec orchestrator python3 -c "from src.stages import STAGE_TRANSITIONS; assert STAGE_TRANSITIONS['testing']['agent'] == 'deployer'"` - [ ] Хардкод `_auto_merge_pr` убран из `_try_advance_stage` - [ ] `curl -s http://localhost:8500/health` → `{"status":"ok"}` - [ ] deployer.md обновлён в enduro-trails repo