48a2e5815f
Co-authored-by: Cursor <cursoragent@cursor.com>
205 lines
6.2 KiB
Bash
Executable File
205 lines
6.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# GitHub upstream → monorepo submodule 최신 소스 반영 (pull only, push 없음)
|
|
#
|
|
# ./git_fetch_all.sh # 4개 submodule fetch + fast-forward
|
|
# ./git_fetch_all.sh --init # submodule 미초기화 시 clone 포함
|
|
# ./git_fetch_all.sh --dry-run # 실행 없이 변경 예상만 출력
|
|
#
|
|
# 대상 (.gitmodules):
|
|
# chatbotApp-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApp (chatbot2.0-agent)
|
|
# chatbotApi-chatbot2.0-agent → KoreaExpressWayCorp/chatbotApi (chatbot2.0-agent)
|
|
# exAiChatBot-chatbot2.0-agent → KoreaExpressWayCorp/exAiChatBot (chatbot2.0-agent)
|
|
# kakaoChatbotSkill-chatbot2.0-agent → KoreaExpressWayCorp/kakaoChatbotSkill (chatbot2.0-agent)
|
|
set -euo pipefail
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
# bare repo 배포 시 상위에서 GIT_DIR 이 export 되면 submodule git 이 깨짐
|
|
MONOREPO_GIT_DIR="${MONOREPO_GIT_DIR:-${GIT_DIR:-}}"
|
|
unset GIT_DIR GIT_WORK_TREE
|
|
INIT=false
|
|
DRY_RUN=false
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--init) INIT=true ;;
|
|
--dry-run) DRY_RUN=true ;;
|
|
-h|--help)
|
|
sed -n '2,14p' "$0"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "알 수 없는 옵션: $arg (--help)"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
log() { echo "[git_fetch_all] $*"; }
|
|
warn() { echo "[git_fetch_all] ⚠️ $*" >&2; }
|
|
|
|
cd "${ROOT_DIR}"
|
|
|
|
if [[ ! -f .gitmodules ]]; then
|
|
echo "ERROR: .gitmodules 없음 — submodule 미설정"
|
|
exit 1
|
|
fi
|
|
|
|
SUBMODULE_PATHS=()
|
|
while IFS= read -r _path; do
|
|
[[ -n "${_path}" ]] && SUBMODULE_PATHS+=("${_path}")
|
|
done < <(git config -f .gitmodules --get-regexp '^submodule\..*\.path$' | awk '{print $2}')
|
|
|
|
if [[ ${#SUBMODULE_PATHS[@]} -eq 0 ]]; then
|
|
echo "ERROR: .gitmodules 에 submodule 경로 없음"
|
|
exit 1
|
|
fi
|
|
|
|
if $INIT && ! $DRY_RUN; then
|
|
log "submodule init (direct clone)..."
|
|
fi
|
|
|
|
resolve_monorepo_git_dir() {
|
|
if [[ -n "${MONOREPO_GIT_DIR}" && -d "${MONOREPO_GIT_DIR}" ]]; then
|
|
echo "${MONOREPO_GIT_DIR}"
|
|
elif git -C "${ROOT_DIR}" rev-parse --git-dir >/dev/null 2>&1; then
|
|
git -C "${ROOT_DIR}" rev-parse --git-dir
|
|
fi
|
|
}
|
|
|
|
submodule_pinned_sha() {
|
|
local path="$1"
|
|
local git_dir
|
|
git_dir="$(resolve_monorepo_git_dir || true)"
|
|
[[ -n "${git_dir}" ]] || return 0
|
|
git --git-dir="${git_dir}" ls-tree HEAD "${path}" 2>/dev/null | awk '{print $3}'
|
|
}
|
|
|
|
clone_submodule_repo() {
|
|
local path="$1" url="$2" branch="$3"
|
|
local target="${ROOT_DIR}/${path}"
|
|
local sha
|
|
|
|
sha="$(submodule_pinned_sha "${path}" || true)"
|
|
log " clone ${url} → ${path} (branch=${branch})"
|
|
rm -rf "${target}"
|
|
if ! git clone --branch "${branch}" --single-branch "${url}" "${target}"; then
|
|
warn "${path} — clone 실패 (서버 GitHub 미접속 시 sync-submodules-rsync.sh 사용)"
|
|
return 1
|
|
fi
|
|
if [[ -n "${sha}" ]]; then
|
|
git -C "${target}" checkout "${sha}" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
restore_monorepo_overlays() {
|
|
if [[ -f "${ROOT_DIR}/local-dev/docker-compose.rag.local.yml" ]]; then
|
|
cp "${ROOT_DIR}/local-dev/docker-compose.rag.local.yml" \
|
|
"${ROOT_DIR}/exAiChatBot-chatbot2.0-agent/docker-compose.local.yml"
|
|
log "복원: exAiChatBot/docker-compose.local.yml (monorepo overlay)"
|
|
fi
|
|
if [[ -f "${ROOT_DIR}/server-dev/docker-compose.rag.server.yml" ]]; then
|
|
cp "${ROOT_DIR}/server-dev/docker-compose.rag.server.yml" \
|
|
"${ROOT_DIR}/exAiChatBot-chatbot2.0-agent/docker-compose.server.yml"
|
|
log "복원: exAiChatBot/docker-compose.server.yml (monorepo overlay)"
|
|
fi
|
|
}
|
|
|
|
submodule_is_cloned() {
|
|
local path="$1"
|
|
[[ -e "${ROOT_DIR}/${path}/.git" ]]
|
|
}
|
|
|
|
fetch_one() {
|
|
local path="$1"
|
|
local url branch old new dirty
|
|
|
|
url="$(git config -f .gitmodules "submodule.${path}.url")"
|
|
branch="$(git config -f .gitmodules "submodule.${path}.branch" || echo main)"
|
|
branch="${branch:-main}"
|
|
|
|
log ">>> ${path}"
|
|
log " url=${url} branch=${branch}"
|
|
|
|
if ! submodule_is_cloned "${path}"; then
|
|
if $DRY_RUN; then
|
|
log " [dry-run] submodule clone 필요 — ./git_fetch_all.sh --init"
|
|
return 0
|
|
fi
|
|
if $INIT; then
|
|
clone_submodule_repo "${path}" "${url}" "${branch}" || return 1
|
|
else
|
|
warn "${path} — submodule 미초기화. --init 옵션 사용"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
(
|
|
cd "${ROOT_DIR}/${path}"
|
|
|
|
if ! git diff --quiet || ! git diff --cached --quiet; then
|
|
dirty=yes
|
|
warn "${path} — 로컬 변경 있음 (fetch는 진행, fast-forward 실패 가능)"
|
|
else
|
|
dirty=no
|
|
fi
|
|
|
|
old="$(git rev-parse HEAD 2>/dev/null || echo none)"
|
|
|
|
if $DRY_RUN; then
|
|
git fetch origin "${branch}" 2>/dev/null || git fetch origin
|
|
new="$(git rev-parse "origin/${branch}" 2>/dev/null || echo unknown)"
|
|
if [[ "${old}" == "${new}" ]]; then
|
|
log " [dry-run] 이미 최신: ${old:0:7}"
|
|
else
|
|
log " [dry-run] ${old:0:7} → ${new:0:7}"
|
|
git log --oneline "${old}..origin/${branch}" 2>/dev/null | sed 's/^/ /' || true
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
git fetch origin "${branch}"
|
|
git checkout "${branch}" 2>/dev/null || git checkout -B "${branch}" "origin/${branch}"
|
|
|
|
if git merge-base --is-ancestor HEAD "origin/${branch}" 2>/dev/null \
|
|
&& [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
|
git merge --ff-only "origin/${branch}"
|
|
elif [[ "$(git rev-parse HEAD)" != "$(git rev-parse "origin/${branch}")" ]]; then
|
|
warn "${path} — fast-forward 불가 (로컬 커밋/변경 존재). 수동 merge 필요"
|
|
git status -sb | sed 's/^/ /'
|
|
exit 1
|
|
fi
|
|
|
|
new="$(git rev-parse HEAD)"
|
|
if [[ "${old}" == "${new}" ]]; then
|
|
log " ✅ 최신 유지 $(git log -1 --oneline)"
|
|
else
|
|
log " ✅ 갱신 ${old:0:7} → ${new:0:7} $(git log -1 --oneline)"
|
|
fi
|
|
)
|
|
}
|
|
|
|
failures=0
|
|
for path in "${SUBMODULE_PATHS[@]}"; do
|
|
if ! fetch_one "${path}"; then
|
|
failures=$((failures + 1))
|
|
fi
|
|
echo ""
|
|
done
|
|
|
|
if ! $DRY_RUN; then
|
|
restore_monorepo_overlays
|
|
fi
|
|
|
|
log "=========================================="
|
|
log "submodule 상태:"
|
|
git submodule status || true
|
|
log "=========================================="
|
|
|
|
if [[ ${failures} -gt 0 ]]; then
|
|
warn "실패 ${failures}개 — 로그 확인"
|
|
exit 1
|
|
fi
|
|
|
|
log "완료 — GitHub → 로컬 반영 (push 없음)"
|
|
log "monorepo 커밋 갱신: git add .gitmodules *-chatbot2.0-agent && git status"
|