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