287 lines
11 KiB
Bash
Executable File
287 lines
11 KiB
Bash
Executable File
#!/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 "Скрипт успешно выполнен!" |