Files
gitea/tools/repo-sync.sh
jiantw83 72ba7b8801 chore(gitea): 技能依結束碼分流,可併行的步驟改成同時跑
技能以前只寫成功路徑。腳本回非 0 時,模型得自己猜下一步,猜錯就是靜靜
往下走。現在每一支腳本在檔頭宣告自己的結束碼,技能也逐碼寫明要停、要
問、還是要改參數再呼叫一次。兩支技能補上連線變數的解析步驟,讓缺值在
第一步就浮出來,而不是在中途撞出一行英文錯誤。

流程也拉平了。取內容、選範本、問輸出位置這幾件事彼此不相依,改成同一批
送出;存取庫批次同步從逐一處理改成各存取庫同時進行,一個 owner 底下有
上百個存取庫時差距最明顯。

相依的技能組下限寫進外掛設定,版本推進。
2026-08-31 11:13:32 +08:00

84 lines
3.3 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env sh
# repo-sync.sh — 把單一存取庫同步到本機。
# 用法: repo-sync.sh <owner>/<repo> [target-dir] # target-dir 預設為 <repo>
# 目錄不存在 → git clone(clone URL 取自 gitea.sh clone-url)
# 目錄已存在 → git fetch、切到基準分支、git pull --ff-only
# 有未提交變更 → 只回報 dirty 與基準分支,不動分支也不 pull
# 基準分支的唯一優先序(呼叫端不必再判斷,也不要自己再推導一次):
# 1. gitea.sh default-branch <owner>/<repo>(該分支要在遠端存在)
# 2. 查不到時依序取遠端的 develop、main、master
# 3. 都沒有 → failed no default branch
# 輸出: 恰好一行,cloned、updated、dirty {分支} 或 failed {原因}。
# 前三種 exit 0;failed exit 1。
# dirty 會把解析好的基準分支一起帶出來,呼叫端直接拿去當 PR 的 base。
# 結束碼: 0=同步完成,輸出是 cloned、updated 或 dirty {分支}
# 1=失敗,輸出是 failed {原因};參數錯誤、clone-url 取不到、fetch/checkout/pull 失敗、
# 以及找不到基準分支都走這一碼。只有 0 與 1 兩種。
set -u
script_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
gitea="$script_dir/gitea.sh"
fail() { # 原因壓成一行,避免呼叫端解析多行輸出
printf 'failed %s\n' "$(printf '%s' "$1" | tr '\n\r\t' ' ')"
exit 1
}
full="${1:-}"
[ -n "$full" ] || fail "usage: repo-sync.sh <owner>/<repo> [target-dir]"
case "$full" in
*/*/*|/*|*/) fail "not owner/repo: $full" ;;
*/*) ;;
*) fail "not owner/repo: $full" ;;
esac
repo="${full#*/}"
target="${2:-$repo}"
remote_has() { # 遠端是否有這個分支
git -C "$target" rev-parse --verify --quiet "refs/remotes/origin/$1" >/dev/null 2>&1
}
if [ ! -e "$target" ]; then
# clone URL 只收 stdout:把 stderr 併進來會讓任何雜訊變成網址的一部分
err=$(mktemp)
url=$("$gitea" clone-url "$full" 2>"$err") || url=''
if [ -z "$url" ]; then
reason=$(cat "$err"); rm -f "$err"
fail "clone-url failed for $full: ${reason:-no clone URL}"
fi
rm -f "$err"
out=$(git clone "$url" "$target" 2>&1) || fail "clone: $out"
printf 'cloned\n'
exit 0
fi
git -C "$target" rev-parse --git-dir >/dev/null 2>&1 || fail "$target is not a git repo"
dirty=0
[ -z "$(git -C "$target" status --porcelain 2>/dev/null)" ] || dirty=1
# dirty 的存取庫也要解析基準分支:呼叫端拿它當 PR 的 base,自己再推導一次就會
# 出現第二套優先序。fetch 只更新 refs,不動工作目錄,dirty 時照樣安全;但 dirty
# 時網路失敗不算致命,還是要把 dirty 回報出去,改用本機既有的 remote refs 判斷。
if ! out=$(git -C "$target" fetch --prune origin 2>&1); then
[ "$dirty" -eq 1 ] || fail "fetch: $out"
fi
branch=$("$gitea" default-branch "$full" 2>/dev/null) || branch=''
if [ -z "$branch" ] || ! remote_has "$branch"; then
branch=''
for b in develop main master; do
if remote_has "$b"; then branch="$b"; break; fi
done
fi
[ -n "$branch" ] || fail "no default branch"
if [ "$dirty" -eq 1 ]; then
printf 'dirty %s\n' "$branch"
exit 0
fi
out=$(git -C "$target" checkout "$branch" 2>&1) || fail "checkout $branch: $out"
out=$(git -C "$target" pull --ff-only origin "$branch" 2>&1) || fail "pull $branch: $out"
printf 'updated\n'