sync_repos.sh

This commit is contained in:
Saravana Achu Mac 2026-04-13 15:10:02 -07:00
parent 7b62411bb3
commit 3fd69decec

149
sync_repos.sh Executable file
View File

@ -0,0 +1,149 @@
#!/bin/bash
set -euo pipefail
ROOT_DIR="$(pwd)"
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
REPORT_TXT="$ROOT_DIR/sync_report_$TIMESTAMP.txt"
REPORT_JSON="$ROOT_DIR/sync_report_$TIMESTAMP.json"
DRY_RUN=false
TIMEOUT=60
# Parse args
for arg in "$@"; do
case $arg in
--dry-run) DRY_RUN=true ;;
--timeout=*) TIMEOUT="${arg#*=}" ;;
esac
done
log() {
echo -e "$1"
echo -e "$1" >> "$REPORT_TXT"
}
json_escape() {
echo "$1" | sed 's/"/\\"/g'
}
run_cmd() {
if $DRY_RUN; then
log "🟡 [DRY-RUN] $*"
return 0
fi
timeout "$TIMEOUT" bash -c "$*" >/dev/null 2>&1
}
echo "Repo Sync Report - $(date)" > "$REPORT_TXT"
echo "[" > "$REPORT_JSON"
FIRST=true
SUCCESS=0
FAIL=0
SKIP=0
for dir in */; do
REPO_PATH="$ROOT_DIR/$dir"
REPO_NAME=$(basename "$dir")
STATUS="unknown"
MESSAGE=""
log "\n🔹 Processing: $REPO_NAME"
cd "$REPO_PATH" || { STATUS="fail"; MESSAGE="cannot cd"; ((FAIL++)); continue; }
if [ ! -d ".git" ]; then
STATUS="skip"; MESSAGE="not a git repo"; ((SKIP++))
log "⚠️ Not a git repo"
continue
fi
if ! git remote get-url origin &>/dev/null; then
STATUS="skip"; MESSAGE="no origin"; ((SKIP++))
log "⚠️ No origin"
continue
fi
# Detect default branch
DEFAULT_BRANCH=$(git remote show origin | awk '/HEAD branch/ {print $NF}')
DEFAULT_BRANCH=${DEFAULT_BRANCH:-main}
if ! git show-ref --verify --quiet "refs/heads/$DEFAULT_BRANCH"; then
STATUS="skip"; MESSAGE="no local $DEFAULT_BRANCH"; ((SKIP++))
log "⚠️ Missing local branch $DEFAULT_BRANCH"
continue
fi
# Check clean working tree
if ! git diff --quiet || ! git diff --cached --quiet; then
STATUS="skip"; MESSAGE="uncommitted changes"; ((SKIP++))
log "⚠️ Uncommitted changes"
continue
fi
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)
if [ "$CURRENT_BRANCH" = "HEAD" ]; then
STATUS="skip"; MESSAGE="detached HEAD"; ((SKIP++))
log "⚠️ Detached HEAD"
continue
fi
# Fetch
if ! run_cmd "git fetch origin --prune"; then
STATUS="fail"; MESSAGE="fetch failed"; ((FAIL++))
log "❌ Fetch failed"
continue
fi
# Checkout default branch
if [ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" ]; then
if ! run_cmd "git checkout $DEFAULT_BRANCH"; then
STATUS="fail"; MESSAGE="checkout failed"; ((FAIL++))
log "❌ Checkout failed"
continue
fi
fi
# Rebase safely
if run_cmd "git rebase origin/$DEFAULT_BRANCH"; then
STATUS="success"; MESSAGE="rebased"
log "✅ Rebased onto origin/$DEFAULT_BRANCH"
((SUCCESS++))
else
git rebase --abort &>/dev/null || true
STATUS="fail"; MESSAGE="rebase conflict"
log "❌ Rebase conflict (aborted)"
((FAIL++))
fi
# Return to original branch
if [ "$CURRENT_BRANCH" != "$DEFAULT_BRANCH" ]; then
run_cmd "git checkout $CURRENT_BRANCH"
fi
# JSON logging
ESC_MSG=$(json_escape "$MESSAGE")
if [ "$FIRST" = true ]; then
FIRST=false
else
echo "," >> "$REPORT_JSON"
fi
echo " {\"repo\":\"$REPO_NAME\",\"status\":\"$STATUS\",\"message\":\"$ESC_MSG\"}" >> "$REPORT_JSON"
done
echo "]" >> "$REPORT_JSON"
log "\n======================================"
log "✅ Success: $SUCCESS"
log "❌ Failed: $FAIL"
log "⚠️ Skipped: $SKIP"
log "📄 TXT Report: $REPORT_TXT"
log "📄 JSON Report: $REPORT_JSON"
echo -e "\nDone."