# .woodpecker.yml trigger: # Запускать каждый час (или как вам нужно) cron: - 'sync-hourly@0 * * * *' # Имя крона@расписание pipeline: sync_releases: image: alpine/git # Базовый образ с git secrets: [ GITEA_TOKEN_RELEASE, github_token ] environment: # GITEA_URL теперь берется из окружения, предоставленного Woodpecker # Мы просто используем ее напрямую в скрипте, если она доступна, # или можно явно присвоить для ясности: # SCRIPT_GITEA_URL: ${WOODPECKER_GITEA_URL} # Явное присваивание для скрипта # Передаем нужные секреты и имя файла GITEA_TOKEN: ${GITEA_TOKEN_RELEASE} # Этот секрет все еще НУЖЕН! GITHUB_TOKEN: ${GITHUB_TOKEN} # Опционально, но рекомендуется REPO_LIST_FILE: repos_to_sync.txt # Имя файла со списком репозиториев commands: # 1. Установка зависимостей (curl и jq) - apk update && apk add curl jq bash # 2. Запуск скрипта синхронизации - | #!/bin/bash set -e # Останавливаться при ошибках # set -x # Для отладки echo "Starting release sync..." # --- Конфигурация --- REPO_FILE="${REPO_LIST_FILE:-repos_to_sync.txt}" # Используем переменную WOODPECKER_GITEA_URL из окружения шага # Если ее нет, скрипт завершится с ошибкой ниже CURRENT_GITEA_URL="${WOODPECKER_GITEA_URL}" # Проверка наличия GITEA_URL (полученного из WOODPECKER_GITEA_URL) if [ -z "$CURRENT_GITEA_URL" ]; then echo "Error: GITEA_URL (from WOODPECKER_GITEA_URL) is not set in the environment!" exit 1 fi # Проверка наличия GITEA_TOKEN (из секрета) if [ -z "$GITEA_TOKEN" ]; then echo "Error: GITEA_TOKEN secret is not set!" exit 1 fi echo "Using Gitea URL: $CURRENT_GITEA_URL" # Заголовок авторизации для Gitea GITEA_AUTH_HEADER="Authorization: token ${GITEA_TOKEN}" # Убираем /api/v1 из базового URL, если он там есть, и добавляем снова GITEA_API_URL="$(echo ${CURRENT_GITEA_URL} | sed 's|/api/v1$||; s|/*$||')/api/v1" echo "Using Gitea API URL: $GITEA_API_URL" # Заголовок авторизации для GitHub (если токен есть) GITHUB_AUTH_HEADER="" if [ -n "$GITHUB_TOKEN" ]; then GITHUB_AUTH_HEADER="Authorization: token ${GITHUB_TOKEN}" fi GITHUB_API_URL="https://api.github.com" # --- Вспомогательные функции (без изменений) --- download_asset() { local url="$1" local filename="$2" echo "Downloading asset: $filename from $url" curl -L -H "$GITHUB_AUTH_HEADER" -o "$filename" "$url" if [ $? -ne 0 ]; then echo "Error downloading asset: $filename" return 1 fi return 0 } upload_asset() { local gitea_repo_path="$1" local release_id="$2" local filename="$3" echo "Uploading asset: $filename to Gitea release ID $release_id" UPLOAD_URL="${GITEA_API_URL}/repos/${gitea_repo_path}/releases/${release_id}/assets?name=$(basename "$filename")" curl -sf --fail -X POST -H "$GITEA_AUTH_HEADER" -H "Content-Type: application/octet-stream" --data-binary "@$filename" "$UPLOAD_URL" if [ $? -ne 0 ]; then echo "Error uploading asset: $filename" return 1 else rm "$filename" return 0 fi } # --- Основной цикл по репозиториям из файла (без изменений) --- if [ ! -f "$REPO_FILE" ]; then echo "Error: Repository list file '$REPO_FILE' not found!" exit 1 fi echo "Reading repository list from $REPO_FILE" while IFS= read -r repo_pair || [[ -n "$repo_pair" ]]; do if [[ -z "$repo_pair" || "$repo_pair" == \#* ]]; then continue; fi if ! echo "$repo_pair" | grep -q ':'; then echo "Warning: Skipping invalid line in $REPO_FILE: $repo_pair" continue fi GITHUB_REPO_PATH=$(echo "$repo_pair" | cut -d':' -f1) GITEA_REPO_PATH=$(echo "$repo_pair" | cut -d':' -f2) echo "-------------------------------------" echo "Syncing releases for $GITHUB_REPO_PATH -> $GITEA_REPO_PATH" # 1. Получаем существующие теги релизов из Gitea echo "Fetching existing Gitea releases for $GITEA_REPO_PATH..." GITEA_RELEASES_JSON=$(curl -sf --fail -H "$GITEA_AUTH_HEADER" "${GITEA_API_URL}/repos/${GITEA_REPO_PATH}/releases") || \ { echo "Error fetching Gitea releases for $GITEA_REPO_PATH. Does the repo exist and token have read access?"; continue; } # Пропускаем репо при ошибке Gitea EXISTING_GITEA_TAGS=$(echo "$GITEA_RELEASES_JSON" | jq -r '.[].tag_name') # 2. Получаем последние релизы из GitHub echo "Fetching latest GitHub releases for $GITHUB_REPO_PATH..." GITHUB_RELEASES_JSON=$(curl -sf --fail -H "$GITHUB_AUTH_HEADER" "${GITHUB_API_URL}/repos/${GITHUB_REPO_PATH}/releases?per_page=20") || \ { echo "Error fetching GitHub releases for $GITHUB_REPO_PATH, skipping this repo."; continue; } # 3. Итерируем по релизам GitHub в ОБРАТНОМ порядке echo "$GITHUB_RELEASES_JSON" | jq -c '.[] | select(.draft == false)' | tac | while IFS= read -r release_json; do TAG_NAME=$(echo "$release_json" | jq -r '.tag_name') # Проверяем, есть ли уже релиз с таким тегом в Gitea if echo "$EXISTING_GITEA_TAGS" | grep -q -x -F "$TAG_NAME"; then continue fi echo ">>> Found new release tag in GitHub: $TAG_NAME. Processing..." RELEASE_NAME=$(echo "$release_json" | jq -r '.name') RELEASE_BODY=$(echo "$release_json" | jq -r '.body // ""') IS_PRERELEASE=$(echo "$release_json" | jq -r '.prerelease') ASSETS=$(echo "$release_json" | jq -c '.assets[]') # 4. Создаем релиз в Gitea echo "Creating release $RELEASE_NAME (tag: $TAG_NAME) in Gitea..." CREATE_PAYLOAD=$(jq -n --arg tag "$TAG_NAME" --arg name "$RELEASE_NAME" --arg body "$RELEASE_BODY" --argjson prerelease "$IS_PRERELEASE" \ '{tag_name: $tag, name: $name, body: $body, prerelease: $prerelease}') GITEA_NEW_RELEASE_JSON=$(curl -sf --fail -X POST -H "$GITEA_AUTH_HEADER" -H "Content-Type: application/json" \ -d "$CREATE_PAYLOAD" \ "${GITEA_API_URL}/repos/${GITEA_REPO_PATH}/releases") if [ $? -ne 0 ]; then echo "Error creating release $TAG_NAME in Gitea for repo $GITEA_REPO_PATH. Check if tag exists in Gitea Git repo and token permissions. Skipping." continue fi GITEA_RELEASE_ID=$(echo "$GITEA_NEW_RELEASE_JSON" | jq -r '.id') echo "Gitea release created with ID: $GITEA_RELEASE_ID" # 5. Скачиваем и загружаем ассеты UPLOAD_FAILED_COUNT=0 if [ -n "$ASSETS" ]; then echo "$ASSETS" | while IFS= read -r asset_json; do ASSET_NAME=$(echo "$asset_json" | jq -r '.name') ASSET_URL=$(echo "$asset_json" | jq -r '.browser_download_url') TMP_ASSET_FILE="asset_${ASSET_NAME}" if download_asset "$ASSET_URL" "$TMP_ASSET_FILE"; then if ! upload_asset "$GITEA_REPO_PATH" "$GITEA_RELEASE_ID" "$TMP_ASSET_FILE"; then ((UPLOAD_FAILED_COUNT++)) fi else echo "Skipping asset $ASSET_NAME due to download error." ((UPLOAD_FAILED_COUNT++)) fi done else echo "No assets found for release $TAG_NAME." fi if [ $UPLOAD_FAILED_COUNT -eq 0 ]; then echo "Successfully processed release $TAG_NAME with all assets."; else echo "Processed release $TAG_NAME, but $UPLOAD_FAILED_COUNT asset(s) failed to download or upload."; fi done # Конец цикла по релизам GitHub echo "Finished sync for $GITHUB_REPO_PATH -> $GITEA_REPO_PATH" echo "-------------------------------------" done < "$REPO_FILE" # Перенаправляем файл в цикл while echo "Release sync finished."