#!/usr/bin/env bash set -euo pipefail # --- Config --- GITHUB_USER="andwati" GITHUB_TOKEN="${GITHUB_TOKEN:?Set GITHUB_TOKEN env var (PAT with repo read access, incl. private repos)}" GITEA_URL="${GITEA_URL:?Set GITEA_URL env var, e.g. https://gitea.andwati.com}" GITEA_TOKEN="${GITEA_TOKEN:?Set GITEA_TOKEN env var (Gitea access token, repo scope)}" GITEA_OWNER="${GITEA_OWNER:-andwati}" MIRROR_INTERVAL="${MIRROR_INTERVAL:-8h0m0s}" # --- Fetch all repos for the GitHub user (paginated), including private ones --- # Uses /user/repos (authenticated, sees private repos owned by the token's user) # rather than /users/{user}/repos (public-only). page=1 repos_json="[]" while :; do resp=$(curl -s -H "Authorization: token ${GITHUB_TOKEN}" \ "https://api.github.com/user/repos?per_page=100&page=${page}&affiliation=owner") count=$(echo "$resp" | jq 'length') [ "$count" -eq 0 ] && break repos_json=$(jq -s '.[0] + .[1]' <(echo "$repos_json") <(echo "$resp")) page=$((page + 1)) done total=$(echo "$repos_json" | jq 'length') echo "Found ${total} repos on GitHub for ${GITHUB_USER}" echo "$repos_json" | jq -c '.[] | {name, private}' | while read -r entry; do name=$(echo "$entry" | jq -r '.name') private=$(echo "$entry" | jq -r '.private') echo "Processing: ${name} (private=${private})" # Check if it already exists in Gitea existing_status=$(curl -s -o /dev/null -w "%{http_code}" \ -H "Authorization: token ${GITEA_TOKEN}" \ "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${name}") if [ "$existing_status" == "200" ]; then echo " Already mirrored, skipping migration (existing mirror syncs on its own schedule)." continue fi http_code=$(curl -s -o /tmp/gitea_migrate_resp.json -w "%{http_code}" \ -X POST "${GITEA_URL}/api/v1/repos/migrate" \ -H "Authorization: token ${GITEA_TOKEN}" \ -H "Content-Type: application/json" \ -d @- <