initial commit

This commit is contained in:
2026-08-18 15:59:40 +03:00
commit 6ba5b43dda
2 changed files with 100 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
name: Mirror GitHub repos to Gitea
on:
schedule:
# Runs at 00:00 UTC daily. Adjust if you want midnight EAT (UTC+3) instead — see note below.
- cron: "0 0 * * *"
workflow_dispatch: {} # allows manual trigger from the Actions tab too
jobs:
mirror:
runs-on: ubuntu-latest
steps:
- name: Checkout (for the script)
uses: actions/checkout@v4
- name: Install jq
run: sudo apt-get update && sudo apt-get install -y jq
- name: Mirror all repos to Gitea
env:
GITHUB_TOKEN: ${{ secrets.GH_PAT }}
GITEA_URL: ${{ secrets.GITEA_URL }}
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
GITEA_OWNER: ${{ secrets.GITEA_OWNER }}
run: |
chmod +x ./mirror-github-to-gitea.sh
./mirror-github-to-gitea.sh
+73
View File
@@ -0,0 +1,73 @@
#!/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 @- <<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."