mirror of
https://github.com/andwati/gitea-mirror-sync.git
synced 2026-10-18 03:12:53 +00:00
93 lines
3.2 KiB
Bash
93 lines
3.2 KiB
Bash
#!/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_resp=$(curl -s -w "\n%{http_code}" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${name}")
|
|
existing_status=$(echo "$existing_resp" | tail -n1)
|
|
existing_body=$(echo "$existing_resp" | sed '$d')
|
|
|
|
if [ "$existing_status" == "200" ]; then
|
|
gitea_private=$(echo "$existing_body" | jq -r '.private')
|
|
|
|
if [ "$gitea_private" != "$private" ]; then
|
|
echo " Already mirrored, but visibility differs (GitHub private=${private}, Gitea private=${gitea_private}). Syncing..."
|
|
patch_code=$(curl -s -o /tmp/gitea_patch_resp.json -w "%{http_code}" \
|
|
-X PATCH "${GITEA_URL}/api/v1/repos/${GITEA_OWNER}/${name}" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"private\": ${private}}")
|
|
|
|
if [ "$patch_code" == "200" ]; then
|
|
echo " Visibility updated to private=${private}."
|
|
else
|
|
echo " Failed to update visibility (HTTP ${patch_code}):"
|
|
cat /tmp/gitea_patch_resp.json
|
|
fi
|
|
else
|
|
echo " Already mirrored, visibility already matches (private=${gitea_private}). Skipping."
|
|
fi
|
|
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 @- <<EOF
|
|
{
|
|
"clone_addr": "https://github.com/${GITHUB_USER}/${name}.git",
|
|
"repo_name": "${name}",
|
|
"repo_owner": "${GITEA_OWNER}",
|
|
"mirror": true,
|
|
"mirror_interval": "${MIRROR_INTERVAL}",
|
|
"private": ${private},
|
|
"service": "github",
|
|
"auth_token": "${GITHUB_TOKEN}"
|
|
}
|
|
EOF
|
|
)
|
|
|
|
if [ "$http_code" == "201" ]; then
|
|
echo " Created mirror (private=${private})."
|
|
else
|
|
echo " Failed (HTTP ${http_code}):"
|
|
cat /tmp/gitea_migrate_resp.json
|
|
fi
|
|
|
|
sleep 1 # be gentle on both APIs
|
|
done
|
|
|
|
echo "Done." |