diff --git a/README.md b/README.md index d3e7830..654aa6d 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,14 @@ npm install npm run build ``` +生产服务器已安装一键更新命令: + +```bash +ameiba-update +``` + +脚本源码位于 `scripts/update-and-restart.sh`。它会先备份 MySQL,再快进拉取 `main`、安装依赖、构建前台与 CMS 管理后台、重启 `ameba-cms`、保存 PM2 进程清单并执行健康检查。若服务器存在未提交的受版本控制文件修改,脚本会停止,避免覆盖人工修改。 + 更新 CMS 后端或后台后,需要在对应目录安装依赖并重启 CMS 进程;仅更新前台 `dist` 不需要重启后端。部署前应备份 MySQL、上传目录和当前构建目录。 ## 联系方式与移动端行为 diff --git a/scripts/update-and-restart.sh b/scripts/update-and-restart.sh new file mode 100755 index 0000000..a354863 --- /dev/null +++ b/scripts/update-and-restart.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +PROJECT_DIR="${AMEIBA_PROJECT_DIR:-/var/www/ameiba-cn-new}" +BRANCH="${AMEIBA_BRANCH:-main}" +BACKUP_DIR="${AMEIBA_BACKUP_DIR:-/var/backups/ameiba-cms}" +CMS_ENV_FILE="$PROJECT_DIR/cms/server/.env" +LOCK_FILE="/var/lock/ameiba-update.lock" + +log() { + printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" +} + +fail() { + log "失败:$*" + exit 1 +} + +command -v git >/dev/null 2>&1 || fail '未安装 git' +command -v npm >/dev/null 2>&1 || fail '未安装 npm' +command -v pm2 >/dev/null 2>&1 || fail '未安装 pm2' +command -v mysqldump >/dev/null 2>&1 || fail '未安装 mysqldump' +command -v curl >/dev/null 2>&1 || fail '未安装 curl' + +exec 9>"$LOCK_FILE" +flock -n 9 || fail '已有更新任务正在运行' + +[[ -d "$PROJECT_DIR/.git" ]] || fail "项目目录不是 Git 仓库:$PROJECT_DIR" +[[ -f "$CMS_ENV_FILE" ]] || fail "CMS 环境变量文件不存在:$CMS_ENV_FILE" + +cd "$PROJECT_DIR" +if ! git diff --quiet || ! git diff --cached --quiet; then + fail '服务器存在未提交的受版本控制文件修改,请先处理后再更新' +fi + +log '备份 MySQL 数据库' +set -a +# shellcheck disable=SC1090 +source "$CMS_ENV_FILE" +set +a +: "${DB_HOST:?DB_HOST 未配置}" +: "${DB_PORT:?DB_PORT 未配置}" +: "${DB_USER:?DB_USER 未配置}" +: "${DB_PASSWORD:?DB_PASSWORD 未配置}" +: "${DB_NAME:?DB_NAME 未配置}" +install -d -m 700 "$BACKUP_DIR" +umask 077 +BACKUP_FILE="$BACKUP_DIR/${DB_NAME}_$(date '+%Y%m%d_%H%M%S').sql.gz" +MYSQL_PWD="$DB_PASSWORD" mysqldump \ + --single-transaction \ + --quick \ + --host="$DB_HOST" \ + --port="$DB_PORT" \ + --user="$DB_USER" \ + "$DB_NAME" | gzip -c > "$BACKUP_FILE" +[[ -s "$BACKUP_FILE" ]] || fail '数据库备份文件为空' +log "数据库已备份:$BACKUP_FILE" + +OLD_COMMIT="$(git rev-parse --short HEAD)" +log "从 origin/$BRANCH 拉取代码(当前 $OLD_COMMIT)" +git fetch origin "$BRANCH" +git pull --ff-only origin "$BRANCH" + +log '安装前台依赖并构建' +npm ci +npm run build + +log '安装 CMS 后端生产依赖' +( + cd "$PROJECT_DIR/cms/server" + npm ci --omit=dev +) + +log '构建 CMS 管理后台' +( + cd "$PROJECT_DIR/cms/admin" + npm ci + npm run build +) + +log '重启 CMS 服务并保存 PM2 进程清单' +pm2 restart ameba-cms --update-env +pm2 save + +log '执行服务健康检查' +curl --fail --silent --show-error --max-time 15 http://127.0.0.1:13001/health >/dev/null +curl --fail --silent --show-error --max-time 20 https://www.ameiba.cn/ >/dev/null + +NEW_COMMIT="$(git rev-parse --short HEAD)" +log "更新完成:$OLD_COMMIT -> $NEW_COMMIT"