Files
Genarrative/scripts/jenkins-deploy-release.sh
2026-04-26 00:07:12 +08:00

192 lines
4.8 KiB
Bash
Raw 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 bash
set -euo pipefail
usage() {
cat <<'EOF'
用法:
./scripts/jenkins-deploy-release.sh --source-dir /path/to/build/123 --deploy-dir /var/lib/jenkins/deploy/Genarrative [--clear-database] [--hook-with-sudo]
说明:
1. 如果部署目录已有旧版本且存在 stop.sh则先执行旧版本 stop.sh。
2. 仅删除并替换发布产物文件,保留部署目录中的运行数据目录。
3. 把指定发布目录中的内容覆盖到部署目录。
4. 如指定 --clear-database则以清库模式执行新版本 start.sh。
5. 最后执行新版本 start.sh。
参数:
--source-dir <path> 必填,待部署的发布目录,例如 build/123
--deploy-dir <path> 必填,固定部署目录,例如 /var/lib/jenkins/deploy/Genarrative
--clear-database 可选,启动新版本时追加 --clear-database
--hook-with-sudo 可选,仅对 start.sh/stop.sh 使用 sudo -n 执行
EOF
}
require_argument() {
local value="$1"
local label="$2"
if [[ -z "${value}" ]]; then
echo "[jenkins-deploy] 缺少参数: ${label}" >&2
exit 1
fi
}
normalize_env_file() {
local env_file="$1"
local temp_file="${env_file}.tmp.$$"
if [[ ! -f "${env_file}" ]]; then
return
fi
# 兼容由 Windows 编辑器或 Jenkins 参数落盘产生的 BOM/CRLF避免 start.sh 加载时报命令不存在。
LC_ALL=C sed $'1s/^\xef\xbb\xbf//;s/\r$//' "${env_file}" >"${temp_file}"
mv "${temp_file}" "${env_file}"
}
normalize_release_env_files() {
local release_dir="$1"
normalize_env_file "${release_dir}/.env"
normalize_env_file "${release_dir}/.env.local"
normalize_env_file "${release_dir}/web/.env"
normalize_env_file "${release_dir}/web/.env.local"
}
SOURCE_DIR=""
DEPLOY_DIR=""
CLEAR_DATABASE="0"
HOOK_WITH_SUDO="0"
DEPLOY_ITEMS=(
".env"
".env.local"
"README.md"
"api-server"
"spacetime_module.wasm"
"start.sh"
"stop.sh"
"web"
"web-server.mjs"
)
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
usage
exit 0
;;
--source-dir)
SOURCE_DIR="${2:?缺少 --source-dir 的值}"
shift 2
;;
--deploy-dir)
DEPLOY_DIR="${2:?缺少 --deploy-dir 的值}"
shift 2
;;
--clear-database)
CLEAR_DATABASE="1"
shift
;;
--hook-with-sudo)
HOOK_WITH_SUDO="1"
shift
;;
*)
echo "[jenkins-deploy] 未知参数: $1" >&2
usage >&2
exit 1
;;
esac
done
require_argument "${SOURCE_DIR}" "--source-dir"
require_argument "${DEPLOY_DIR}" "--deploy-dir"
run_hook() {
local hook_dir="$1"
local hook_name="$2"
shift 2
local hook_path="${hook_dir}/${hook_name}"
if [[ ! -x "${hook_path}" ]]; then
echo "[jenkins-deploy] hook 不存在或不可执行: ${hook_path}" >&2
exit 1
fi
# 仅在启停脚本阶段使用 sudo文件清理与移动仍保持普通权限避免放大授权范围。
if [[ "${HOOK_WITH_SUDO}" == "1" ]]; then
echo "[jenkins-deploy] 使用 sudo 执行 ${hook_name}: ${hook_path}"
(
cd "${hook_dir}"
sudo -n "${hook_path}" "$@"
) || {
echo "[jenkins-deploy] sudo 执行 ${hook_name} 失败,请确认 jenkins 用户已配置免密 sudo 权限。" >&2
exit 1
}
return
fi
(
cd "${hook_dir}"
"./${hook_name}" "$@"
)
}
if [[ ! -d "${SOURCE_DIR}" ]]; then
echo "[jenkins-deploy] 发布目录不存在: ${SOURCE_DIR}" >&2
exit 1
fi
SOURCE_DIR="$(cd "${SOURCE_DIR}" && pwd)"
mkdir -p "${DEPLOY_DIR}"
DEPLOY_DIR="$(cd "${DEPLOY_DIR}" && pwd)"
if [[ ! -f "${SOURCE_DIR}/start.sh" ]]; then
echo "[jenkins-deploy] 发布目录缺少 start.sh: ${SOURCE_DIR}" >&2
exit 1
fi
normalize_release_env_files "${SOURCE_DIR}"
if [[ -x "${DEPLOY_DIR}/stop.sh" ]]; then
echo "[jenkins-deploy] 先停止旧版本: ${DEPLOY_DIR}"
run_hook "${DEPLOY_DIR}" "stop.sh"
else
echo "[jenkins-deploy] 部署目录无可执行 stop.sh跳过停服"
fi
echo "[jenkins-deploy] 清空部署目录: ${DEPLOY_DIR}"
for item in "${DEPLOY_ITEMS[@]}"; do
if [[ -e "${DEPLOY_DIR}/${item}" ]]; then
echo "[jenkins-deploy] 删除旧产物: ${DEPLOY_DIR}/${item}"
rm -rf "${DEPLOY_DIR:?}/${item}"
fi
done
echo "[jenkins-deploy] 移动发布内容: ${SOURCE_DIR} -> ${DEPLOY_DIR}"
for item in "${DEPLOY_ITEMS[@]}"; do
if [[ -e "${SOURCE_DIR}/${item}" ]]; then
echo "[jenkins-deploy] 覆盖产物: ${item}"
mv "${SOURCE_DIR}/${item}" "${DEPLOY_DIR}/"
fi
done
chmod +x "${DEPLOY_DIR}/start.sh"
if [[ -f "${DEPLOY_DIR}/stop.sh" ]]; then
chmod +x "${DEPLOY_DIR}/stop.sh"
fi
normalize_release_env_files "${DEPLOY_DIR}"
echo "[jenkins-deploy] 启动新版本: ${DEPLOY_DIR}"
if [[ "${CLEAR_DATABASE}" == "1" ]]; then
echo "[jenkins-deploy] 以清库模式启动新版本"
run_hook "${DEPLOY_DIR}" "start.sh" --clear-database
else
run_hook "${DEPLOY_DIR}" "start.sh"
fi
echo "[jenkins-deploy] 完成"