Files
crearte-monorepo/clone_all.sh
T
XingfenD cc2156b44d fix(clone): pin master as the bootstrap branch for crearte and crearte-server
The pins still named the feat/submission-preview work branch, so fresh
clones landed on WIP instead of the integration branch.
2026-09-29 21:38:48 +08:00

130 lines
3.8 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# clone_all.sh — clone (or update) every project in this workspace.
#
# Idempotent, safe to re-run:
# - directory missing / not a git repo -> git clone --branch <branch>
# - directory already a git repo -> fetch + fast-forward to <branch>
#
# Usage:
# ./clone_all.sh # clone or update all projects
# CLONE_PROTO=https ./clone_all.sh # rewrite URLs to https (no SSH key needed)
set -uo pipefail
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR" || exit 1
# ---------------------------------------------------------------------------
# Project list: "<dir-name>|<git-url>|<branch>"
# ---------------------------------------------------------------------------
REPOS=(
"crearte|git@github.com:XingfenD/crearte.git|master"
"crearte-server|git@github.com:XingfenD/crearte-server.git|master"
"crearte-deploy|git@github.com:XingfenD/crearte-deploy.git|master"
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
if [ -t 1 ]; then
C_OK=$'\033[32m'; C_WARN=$'\033[33m'; C_ERR=$'\033[31m'; C_OFF=$'\033[0m'
else
C_OK=''; C_WARN=''; C_ERR=''; C_OFF=''
fi
info() { printf '==> %s\n' "$*"; }
ok() { printf "${C_OK} ok${C_OFF} %s\n" "$*"; }
warn() { printf "${C_WARN} warn${C_OFF} %s\n" "$*"; }
err() { printf "${C_ERR} error${C_OFF} %s\n" "$*" >&2; }
# ssh url -> https url when the caller asked for it
resolve_url() {
local url="$1"
if [ "${CLONE_PROTO:-ssh}" = "https" ]; then
url="${url#git@}"
url="${url/://}"
url="https://$url"
fi
printf '%s' "$url"
}
has_local_changes() {
local dir="$1"
[ -n "$(git -C "$dir" status --porcelain 2>/dev/null)" ]
}
# ---------------------------------------------------------------------------
# Actions
# ---------------------------------------------------------------------------
clone_repo() {
local dir="$1" url="$2" branch="$3"
info "$dir: cloning $branch from $url"
if git clone --branch "$branch" "$url" "$dir"; then
ok "$dir cloned"
return 0
fi
err "$dir clone failed"
return 1
}
update_repo() {
local dir="$1" branch="$2"
info "$dir: updating $branch"
if ! git -C "$dir" fetch --prune origin; then
err "$dir fetch failed (network or credentials?)"
return 1
fi
local current
current="$(git -C "$dir" rev-parse --abbrev-ref HEAD)"
if [ "$current" != "$branch" ]; then
if has_local_changes "$dir"; then
warn "$dir has uncommitted changes on '$current' — skipping branch switch to '$branch'"
return 0
fi
if ! git -C "$dir" checkout "$branch"; then
err "$dir could not switch to '$branch'"
return 1
fi
fi
if ! git -C "$dir" pull --ff-only origin "$branch"; then
err "$dir not fast-forwardable — resolve manually (git -C $dir status)"
return 1
fi
ok "$dir up to date"
return 0
}
# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
cloned=0 updated=0 skipped=0 failed=0
for entry in "${REPOS[@]}"; do
IFS='|' read -r dir url branch <<< "$entry"
if [ -d "$dir/.git" ] || git -C "$dir" rev-parse --git-dir >/dev/null 2>&1; then
if update_repo "$dir" "$branch"; then
updated=$((updated + 1))
else
failed=$((failed + 1))
fi
elif [ -e "$dir" ]; then
warn "$dir exists but is not a git repo — skipping (move it away or delete it)"
skipped=$((skipped + 1))
else
if clone_repo "$dir" "$(resolve_url "$url")" "$branch"; then
cloned=$((cloned + 1))
else
failed=$((failed + 1))
fi
fi
done
printf '\nSummary: %d cloned, %d updated, %d skipped, %d failed\n' \
"$cloned" "$updated" "$skipped" "$failed"
[ "$failed" -eq 0 ]