Files
homebox_lens/gitea-client.zsh
2025-09-05 10:42:55 +03:00

213 lines
8.8 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env zsh
# ==============================================================================
# Gitea Client Wrapper (gitea-client.zsh) - FULLY FEATURED
#
# PURPOSE:
# Высокоуровневая, отказоустойчивая обертка над 'tea' для
# использования AI-агентами. Абстрагирует сложность управления
# контекстом, предоставляет атомарные операции и прозрачный вывод.
#
# VERSION: 1.4
# CHANGE LOG:
# - v1.4: Добавлены критически важные функции 'create-task' и 'create-pr',
# чтобы полностью соответствовать архитектуре системы
# 'AI_Dev_System_Ivanov_Gemini_v1.1'.
# - v1.3: Исправлена критическая ошибка парсинга remote URL,
# когда в SSH адресе присутствует номер порта.
# Логика `initialize` полностью переработана для надежности.
# ==============================================================================
# --- ОБРАБОТКА ОШИБОК И ВЫХОД ---
set -e
set -u
set -o pipefail
# --- ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ И НАСТРОЙКИ ---
ROLE_NAME=""
REPO_SLUG=""
VERBOSE="true"
# --- ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ ---
log_info() {
if [[ "$VERBOSE" == "true" ]]; then
echo -e "\033[34m[INFO]\033[0m $1" >&2
fi
}
error_exit() {
echo -e "\033[31m[ОШИБКА ЛОГИКИ]\033[0m $1" >&2
exit 1
}
# --- ЦЕНТРАЛИЗОВАННЫЙ ИСПОЛНИТЕЛЬ КОМАНД ---
run_command() {
log_info "Выполняется команда:"
echo -e "\033[33m[CMD]\033[0m $@" >&2
local output
local exit_code
output=$("$@" 2>&1)
exit_code=$?
if [[ $exit_code -ne 0 ]]; then
echo -e "\033[31m[ОШИБКА ВЫПОЛНЕНИЯ]\033[0m Команда завершилась с кодом $exit_code." >&2
echo "------------------------- ВЫВОД КОМАНДЫ -------------------------" >&2
echo "$output" >&2
echo "-----------------------------------------------------------------" >&2
exit $exit_code
fi
echo "$output"
}
# --- ИНИЦИАЛИЗАЦИЯ И ПРОВЕРКИ ---
initialize() {
log_info "Инициализация клиента..."
for cmd in git tea jq; do
command -v "$cmd" >/dev/null 2>&1 || error_exit "Зависимость не найдена: $cmd. Пожалуйста, установите ее."
done
local git_remote_url
git_remote_url=$(run_command git remote get-url origin) || error_exit "Не удалось определить remote URL."
# Надежная логика парсинга для SSH и HTTPS URL
local path_part=$(echo "$git_remote_url" | sed -n 's|.*//[^/]*/\(.*\)|\1|p')
if [[ -z "$path_part" ]]; then
path_part=$(echo "$git_remote_url" | sed -n 's|.*:\(.*\)|
\1|p')
fi
REPO_SLUG=$(echo "$path_part" | sed 's/\.git$//')
[[ -z "$REPO_SLUG" ]] && error_exit "Не удалось извлечь 'owner/repo' из URL: $git_remote_url"
log_info "Репозиторий определен как: $REPO_SLUG"
[[ -z "$ROLE_NAME" ]] && error_exit "Имя роли (ROLE_NAME) не было предоставлено."
log_info "Роль установлена: $ROLE_NAME"
}
# --- ФУНКЦИИ КОМАНД ---
create_task() {
local title="" body="" assignee="" labels=""
while [[ $# -gt 0 ]]; do case $1 in
--title) title="$2"; shift 2;;
--body) body="$2"; shift 2;;
--assignee) assignee="$2"; shift 2;;
--labels) labels="$2"; shift 2;;
*) shift;;
esac; done
[[ -z "$title" || -z "$body" || -z "$assignee" || -z "$labels" ]] && error_exit "Для 'create-task' требуются флаги --title, --body, --assignee, --labels."
log_info "Создание задачи для '$assignee'..."
run_command tea issues create --repo "$REPO_SLUG" \
--title "$title" \
--description "$body" \
--assignees "$assignee" \
--labels "$labels"
log_info "Задача успешно создана."
}
create_pr() {
local title="" body="" head="" base="main"
while [[ $# -gt 0 ]]; do case $1 in
--title) title="$2"; shift 2;;
--body) body="$2"; shift 2;;
--head) head="$2"; shift 2;;
--base) base="$2"; shift 2;;
*) shift;;
esac; done
[[ -z "$title" || -z "$body" || -z "$head" ]] && error_exit "Для 'create-pr' требуются флаги --title, --body, --head."
log_info "Создание Pull Request из ветки '$head' в '$base' ભા"
run_command tea pr create --repo "$REPO_SLUG" \
--title "$title" \
--description "$body" \
--head "$head" \
--base "$base"
log_info "Pull Request успешно создан."
}
find_tasks() {
local task_type=""
while [[ $# -gt 0 ]]; do case $1 in --type) task_type="$2"; shift 2;; *) shift;; esac; done
[[ -z "$task_type" ]] && error_exit "Для 'find-tasks' требуется флаг --type."
local issues_json
issues_json=$(run_command tea issues list --output json --repo "$REPO_SLUG" --labels "$task_type" --state "open")
if [[ -z "$issues_json" || "$issues_json" == "[]" ]]; then
echo "[]"
else
echo "$issues_json" | jq -c '.[] | select(.labels[]?.name == "status::pending")'
fi
}
update_task_status() {
local issue_id="" old_status="" new_status=""
while [[ $# -gt 0 ]]; do case $1 in --issue-id) issue_id="$2"; shift 2;; --old) old_status="$2"; shift 2;; --new) new_status="$2"; shift 2;; *) shift;; esac; done
[[ -z "$issue_id" || -z "$old_status" || -z "$new_status" ]] && error_exit "Для 'update-task-status' требуются флаги --issue-id, --old, --new."
run_command tea issues edit "$issue_id" --repo "$REPO_SLUG" --remove-labels "$old_status" --add-labels "$new_status"
log_info "Статус задачи #$issue_id успешно обновлен на '$new_status'."
}
merge_and_complete() {
local issue_id="" pr_id="" branch_name=""
while [[ $# -gt 0 ]]; do case $1 in --issue-id) issue_id="$2"; shift 2;; --pr-id) pr_id="$2"; shift 2;; --branch) branch_name="$2"; shift 2;; *) shift;; esac; done
[[ -z "$issue_id" || -z "$pr_id" || -z "$branch_name" ]] && error_exit "Для 'merge-and-complete' требуются флаги --issue-id, --pr-id, --branch."
log_info "Слияние PR #$pr_id..."
run_command tea pr merge "$pr_id" --repo "$REPO_SLUG"
log_info "Удаление ветки '$branch_name'..."
run_command git push origin --delete "$branch_name"
log_info "Закрытие задачи #$issue_id..."
run_command tea issues close "$issue_id" --repo "$REPO_SLUG"
log_info "Процесс успешно завершен."
}
return_to_dev() {
local issue_id="" pr_id="" report=""
while [[ $# -gt 0 ]]; do case $1 in --issue-id) issue_id="$2"; shift 2;; --pr-id) pr_id="$2"; shift 2;; --report) report="$2"; shift 2;; *) shift;; esac; done
[[ -z "$issue_id" || -z "$pr_id" || -z "$report" ]] && error_exit "Для 'return-to-dev' требуются флаги --issue-id, --pr-id, --report."
log_info "Отклонение PR #$pr_id..."
run_command tea pr close "$pr_id" --repo "$REPO_SLUG"
log_info "Добавление отчета о дефектах в задачу #$issue_id..."
run_command tea issues comment create "$issue_id" --repo "$REPO_SLUG" --comment "$report"
log_info "Возврат задачи #$issue_id разработчику..."
run_command tea issues edit "$issue_id" --repo "$REPO_SLUG" \
--title "[QA -> DEV] FAILED: Fix Defects in PR #$pr_id" \
--assignee "agent-developer" \
--remove-labels "status::in-progress,type::quality-assurance" \
--add-labels "status::failed,type::development"
log_info "Задача возвращена."
}
# --- ГЛАВНЫЙ ДИСПЕТЧЕР КОМАНД ---
main() {
[[ $# -lt 2 ]] && error_exit "Неверное использование. Требуется: ./gitea-client.zsh <ROLE_NAME> <COMMAND> [OPTIONS]"
ROLE_NAME="$1"; shift
local COMMAND="$1"; shift
initialize
case "$COMMAND" in
create-task) create_task "$@";;
create-pr) create_pr "$@";;
find-tasks) find_tasks "$@";;
update-task-status) update_task_status "$@";;
merge-and-complete) merge_and_complete "$@";;
return-to-dev) return_to_dev "$@";;
*) error_exit "Неизвестная команда: '$COMMAND'";;
esac
}
# --- ТОЧКА ВХОДА ---
main "$@"