#!/usr/bin/env bash # datahub 更新脚本:git pull + 智能重建 + 滚动重启 # # 用法:bash update.sh [选项] # --force-rebuild 不看 git diff,强制重建所有镜像 # --skip-migrate 检测到新迁移时不提示,直接跳过 set -euo pipefail B='\033[34m'; G='\033[32m'; Y='\033[33m'; R='\033[31m'; N='\033[0m' step() { echo -e "\n${B}=> $*${N}"; } ok() { echo -e "${G}[OK]${N} $*"; } warn() { echo -e "${Y}[!]${N} $*"; } err() { echo -e "${R}[ERR]${N} $*" >&2; } FORCE_REBUILD=false SKIP_MIGRATE=false for arg in "$@"; do case "$arg" in --force-rebuild) FORCE_REBUILD=true ;; --skip-migrate) SKIP_MIGRATE=true ;; -h|--help) sed -n '2,7p' "$0" exit 0 ;; *) echo "未知参数: $arg" >&2; exit 1 ;; esac done SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) REPO_ROOT=$(cd "$SCRIPT_DIR/../../.." && pwd) QUADLET_DIR="$HOME/.config/containers/systemd" cd "$REPO_ROOT" # 1. 必须是 git 仓库且工作区干净 if [ ! -d .git ]; then err "$REPO_ROOT 不是 git 仓库" exit 1 fi if ! git diff --quiet || ! git diff --cached --quiet; then err "工作区有未提交的变更,先 stash 或 commit" git status --short exit 1 fi # 2. git pull step "git pull" OLD_HEAD=$(git rev-parse HEAD) git pull --ff-only NEW_HEAD=$(git rev-parse HEAD) if [ "$OLD_HEAD" = "$NEW_HEAD" ] && [ "$FORCE_REBUILD" = false ]; then ok "代码已是最新,无需更新(如需强制重建请加 --force-rebuild)" exit 0 fi # 3. 检测变更范围 if [ "$FORCE_REBUILD" = true ]; then CH_BACKEND=true; CH_FRONTEND=true; CH_QUADLET=true CH_PG_IMAGE=true; CH_MIGRATIONS=true warn "强制重建:忽略 git diff" else DIFF=$(git diff --name-only "$OLD_HEAD" "$NEW_HEAD") matches() { echo "$DIFF" | grep -qE "$1"; } CH_BACKEND=$(matches '^backend/' && echo true || echo false) CH_FRONTEND=$(matches '^(frontend/|deploy/podman/images/frontend/)' && echo true || echo false) CH_QUADLET=$(matches '^deploy/podman/quadlet/' && echo true || echo false) CH_PG_IMAGE=$(matches '^deploy/podman/images/postgres/' && echo true || echo false) CH_MIGRATIONS=$(matches '^backend/migrations/' && echo true || echo false) fi echo echo "变更检测:" printf " %-20s %s\n" "backend image:" "$CH_BACKEND" printf " %-20s %s\n" "frontend image:" "$CH_FRONTEND" printf " %-20s %s\n" "postgres image:" "$CH_PG_IMAGE" printf " %-20s %s\n" "quadlet files:" "$CH_QUADLET" printf " %-20s %s\n" "migrations:" "$CH_MIGRATIONS" # 4. 重建镜像 if [ "$CH_PG_IMAGE" = "true" ]; then step "重建 postgres 镜像" podman build -t localhost/datahub-postgres:latest \ -f deploy/podman/images/postgres/Dockerfile . fi if [ "$CH_BACKEND" = "true" ]; then step "重建 backend 镜像" podman build -t localhost/datahub-backend:latest \ -f backend/Dockerfile backend/ fi if [ "$CH_FRONTEND" = "true" ]; then step "重建 frontend 镜像" podman build -t localhost/datahub-frontend:latest \ -f deploy/podman/images/frontend/Dockerfile . fi # 5. 同步 Quadlet(任何 quadlet 改动或强制时) if [ "$CH_QUADLET" = "true" ] || [ "$FORCE_REBUILD" = true ]; then step "同步 Quadlet 单元" cp deploy/podman/quadlet/* "$QUADLET_DIR/" systemctl --user daemon-reload ok "Quadlet 已更新" fi # 6. 滚动重启受影响的服务 step "重启受影响的服务" restart_svc() { local svc=$1 echo " 重启 $svc.service" systemctl --user restart "$svc.service" sleep 2 if ! systemctl --user is-active --quiet "$svc.service"; then err "$svc 重启失败" journalctl --user -u "$svc.service" -n 40 --no-pager exit 1 fi } [ "$CH_PG_IMAGE" = "true" ] && restart_svc datahub-postgres [ "$CH_BACKEND" = "true" ] && restart_svc datahub-backend [ "$CH_FRONTEND" = "true" ] && restart_svc datahub-frontend # Quadlet 改了但镜像没改时,仍需重启对应服务 if [ "$CH_QUADLET" = "true" ]; then DIFF_Q=$(git diff --name-only "$OLD_HEAD" "$NEW_HEAD" -- deploy/podman/quadlet/ 2>/dev/null || true) [ "$CH_PG_IMAGE" = "false" ] && echo "$DIFF_Q" | grep -q "datahub-postgres" && restart_svc datahub-postgres [ "$CH_BACKEND" = "false" ] && echo "$DIFF_Q" | grep -q "datahub-backend" && restart_svc datahub-backend [ "$CH_FRONTEND" = "false" ] && echo "$DIFF_Q" | grep -q "datahub-frontend" && restart_svc datahub-frontend echo "$DIFF_Q" | grep -q "datahub-rabbitmq" && restart_svc datahub-rabbitmq fi # 7. 迁移提示 if [ "$CH_MIGRATIONS" = "true" ] && [ "$SKIP_MIGRATE" = false ]; then echo warn "检测到新迁移文件:" git diff --name-only "$OLD_HEAD" "$NEW_HEAD" -- backend/migrations/ | sed 's/^/ /' read -rp "立即执行迁移?(Y/n): " ans ans="${ans,,}" if [[ -z "$ans" || "$ans" == "y" ]]; then podman exec -it datahub-backend php bin/hyperf.php migrate ok "迁移完成" else warn "跳过。后续可手动执行:podman exec -it datahub-backend php bin/hyperf.php migrate" fi elif [ "$CH_MIGRATIONS" = "true" ]; then warn "检测到新迁移但已 --skip-migrate,请手动执行" fi echo ok "更新完成" echo " $OLD_HEAD" echo " → $NEW_HEAD"