gitea_client
This commit is contained in:
213
gitea-client.zsh
Executable file
213
gitea-client.zsh
Executable file
@@ -0,0 +1,213 @@
|
||||
#!/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 "$@"
|
||||
Reference in New Issue
Block a user