sync_repos.sh
This commit is contained in:
parent
7b62411bb3
commit
3fd69decec
149
sync_repos.sh
Executable file
149
sync_repos.sh
Executable 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."
|
||||||
Loading…
Reference in New Issue
Block a user