#!/bin/bash # Скрипт для создания группы, репозитория и копирования кода в GitLab # с назначением прав пользователю из Keycloak set -e # Прерывать выполнение при ошибках # === КОНФИГУРАЦИЯ === # GitLab Private Token с правами администратора PRIVATE_TOKEN=$1 # Пользователь из Keycloak (должен существовать в GitLab) KEYCLOAK_USERNAME=$2 USER_ID=${KEYCLOAK_USERNAME} GITLAB_URL="https://gitlab.oa2.ru" # URL вашего GitLab # Данные для новой группы и репозитория GROUP_NAME="group-${USER_ID}" GROUP_PATH="group-${USER_ID}" # Может отличаться от имени GROUP_DESCRIPTION="Группа для пользователя ${USER_ID}" # Данные для нового репозитория PROJECT_NAME="task1" PROJECT_DESCRIPTION="Репозиторий с кодом task1" # Внешний репозиторий для копирования SOURCE_REPO_URL="https://git.oa2.ru/dzyk/task1" # Замените на реальный URL # Уровень доступа для пользователя (owner = 50) ACCESS_LEVEL=50 # Временная директория для клонирования TEMP_DIR="/tmp/gitlab-migration-$(date +%s)" # === ФУНКЦИИ === # Функция для логирования log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" } # Функция для выполнения HTTP запросов к GitLab API gitlab_api() { local method=$1 local endpoint=$2 local data=$3 local curl_cmd="curl -s -X $method \ '$GITLAB_URL/api/v4$endpoint' \ -H 'Private-Token: $PRIVATE_TOKEN' \ -H 'Content-Type: application/json'" if [ ! -z "$data" ]; then curl_cmd="$curl_cmd -d '$data'" fi eval $curl_cmd } # Функция для проверки ошибок API check_api_error() { local response=$1 local operation=$2 if echo "$response" | jq -e '.error' > /dev/null 2>&1; then error_msg=$(echo "$response" | jq -r '.error') log "Ошибка при $operation: $error_msg" return 1 fi if echo "$response" | jq -e '.message' > /dev/null 2>&1; then error_msg=$(echo "$response" | jq -r '.message') if [ "$error_msg" != "null" ] && [ ! -z "$error_msg" ]; then log "Ошибка при $operation: $error_msg" return 1 fi fi return 0 } # === ОСНОВНОЙ СКРИПТ === log "Начало выполнения скрипта" # 1. Проверка зависимостей log "Проверка зависимостей..." for cmd in curl jq git; do if ! command -v $cmd &> /dev/null; then log "Ошибка: $cmd не установлен" exit 1 fi done log "Все зависимости установлены" # 2. Поиск пользователя из Keycloak log "Поиск пользователя '$KEYCLOAK_USERNAME' в GitLab..." user_search=$(gitlab_api "GET" "/users?username=$KEYCLOAK_USERNAME") if ! check_api_error "$user_search" "поиске пользователя"; then exit 1 fi user_id=$(echo "$user_search" | jq -r '.[0].id') user_username=$(echo "$user_search" | jq -r '.[0].username') if [ "$user_id" = "null" ] || [ -z "$user_id" ]; then log "Ошибка: Пользователь '$KEYCLOAK_USERNAME' не найден в GitLab" log "Убедитесь, что пользователь вошел через Keycloak хотя бы один раз" exit 1 fi log "Найден пользователь: $user_username (ID: $user_id)" # 4. Создание группы log "Проверка существования группы '$GROUP_NAME'..." group_check=$(gitlab_api "GET" "/groups/$GROUP_PATH") if echo "$group_check" | jq -e '.id' > /dev/null 2>&1; then group_id=$(echo "$group_check" | jq -r '.id') log "Группа '$GROUP_NAME' уже существует (ID: $group_id)" else log "Создание группы '$GROUP_NAME'..." group_data=$(jq -n \ --arg name "$GROUP_NAME" \ --arg path "$GROUP_PATH" \ --arg desc "$GROUP_DESCRIPTION" \ --arg visibility "private" \ '{ name: $name, path: $path, description: $desc, visibility: $visibility, lfs_enabled: true, request_access_enabled: true }') create_group=$(gitlab_api "POST" "/groups" "$group_data") if ! check_api_error "$create_group" "создании группы"; then exit 1 fi group_id=$(echo "$create_group" | jq -r '.id') log "Группа создана успешно (ID: $group_id)" fi # 5. Создание проекта в группе log "Проверка существования проекта '$PROJECT_NAME' в группе..." project_check=$(gitlab_api "GET" "/projects/$GROUP_PATH%2F$PROJECT_NAME") if echo "$project_check" | jq -e '.id' > /dev/null 2>&1; then project_id=$(echo "$project_check" | jq -r '.id') log "Проект '$PROJECT_NAME' уже существует (ID: $project_id)" else log "Создание проекта '$PROJECT_NAME' в группе..." project_data=$(jq -n \ --arg name "$PROJECT_NAME" \ --arg path "$PROJECT_NAME" \ --arg desc "$PROJECT_DESCRIPTION" \ --arg namespace_id "$group_id" \ --arg visibility "private" \ '{ name: $name, path: $path, description: $desc, namespace_id: $namespace_id, visibility: $visibility, initialize_with_readme: false, lfs_enabled: true, container_registry_enabled: true }') create_project=$(gitlab_api "POST" "/projects" "$project_data") if ! check_api_error "$create_project" "создании проекта"; then exit 1 fi project_id=$(echo "$create_project" | jq -r '.id') project_ssh_url=$(echo "$create_project" | jq -r '.ssh_url_to_repo') project_http_url=$(echo "$create_project" | jq -r '.http_url_to_repo') log "Проект создан успешно (ID: $project_id)" log "URL проекта: $project_http_url" fi # 6. Назначение прав пользователю как owner группы log "Проверка прав пользователя $user_username в группе..." group_members=$(gitlab_api "GET" "/groups/$group_id/members") user_in_group=$(echo "$group_members" | jq --arg user_id "$user_id" '.[] | select(.id == ($user_id|tonumber))') if [ -z "$user_in_group" ]; then log "Назначение прав owner пользователю $user_username в группе..." member_data=$(jq -n \ --arg user_id "$user_id" \ --arg access_level "$ACCESS_LEVEL" \ '{ user_id: $user_id, access_level: ($access_level|tonumber) }') add_member=$(gitlab_api "POST" "/groups/$group_id/members" "$member_data") if ! check_api_error "$add_member" "добавлении пользователя в группу"; then exit 1 fi log "Пользователю $user_username назначены права owner в группе" else current_access=$(echo "$user_in_group" | jq -r '.access_level') if [ "$current_access" != "$ACCESS_LEVEL" ]; then log "Обновление прав пользователя $user_username с уровня $current_access на $ACCESS_LEVEL..." member_data=$(jq -n \ --arg access_level "$ACCESS_LEVEL" \ '{ access_level: ($access_level|tonumber) }') update_member=$(gitlab_api "PUT" "/groups/$group_id/members/$user_id" "$member_data") if ! check_api_error "$update_member" "обновлении прав пользователя"; then exit 1 fi log "Права пользователя обновлены" else log "Пользователь $user_username уже имеет права owner в группе" fi fi # 7. Клонирование и копирование кода log "Создание временной директории: $TEMP_DIR" mkdir -p "$TEMP_DIR" cd "$TEMP_DIR" log "Клонирование исходного репозитория: $SOURCE_REPO_URL" if ! git clone --bare "$SOURCE_REPO_URL" source-repo.git; then log "Ошибка при клонировании исходного репозитория" exit 1 fi log "Клонирование целевого репозитория GitLab" # Получаем URL репозитория с токеном для записи repo_url_with_token=$(echo "$project_http_url" | sed "s|https://|https://gitlab-ci-token:$PRIVATE_TOKEN@|") if ! git clone "$repo_url_with_token" target-repo; then log "Ошибка при клонировании целевого репозитория" exit 1 fi cd target-repo log "Добавление remote исходного репозитория" git remote add source ../source-repo.git log "Получение данных из исходного репозитория" git fetch source log "Объединение всех веток из исходного репозитория" for branch in $(git branch -r | grep 'source/' | sed 's|source/||'); do if [ "$branch" != "HEAD" ] && [ "$branch" != "->" ]; then log " Копирование ветки: $branch" git checkout -b "$branch" "source/$branch" 2>/dev/null || git branch "$branch" "source/$branch" fi done # Возвращаемся в основную ветку (если есть) if git show-ref --verify --quiet refs/heads/main; then git checkout main elif git show-ref --verify --quiet refs/heads/master; then git checkout master fi log "Отправка всех веток в GitLab" git push --all origin git push --tags origin log "Очистка временных файлов" cd / rm -rf "$TEMP_DIR" # 8. Проверка результата log "Проверка созданной структуры..." final_check=$(gitlab_api "GET" "/projects/$project_id") project_name=$(echo "$final_check" | jq -r '.name_with_namespace') web_url=$(echo "$final_check" | jq -r '.web_url') log "=== ОТЧЕТ ===" log "Группа: $GROUP_NAME (ID: $group_id)" log "Проект: $project_name (ID: $project_id)" log "URL проекта: $web_url" log "Пользователь с правами owner: $user_username" log "Код скопирован из: $SOURCE_REPO_URL" log "" log "Скрипт успешно выполнен!"