订单配置
This commit is contained in:
1 parent
e81481623c
commit
c7f43e30a9
11 files changed
+492
-19
No files matched your search
Executable
+193
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Mac / Linux 版一键部署,行为与 deploy.ps1 一致。
|
||||
#
|
||||
# ./deploy/deploy.sh api 只部署服务端
|
||||
# ./deploy/deploy.sh admin 只部署管理端
|
||||
# ./deploy/deploy.sh 两个都部署
|
||||
# ./deploy/deploy.sh api --dry-run 只打包、只显示会上传什么,不真传
|
||||
# ./deploy/deploy.sh api --with-install 顺带装依赖(只有改了 package.json 才需要)
|
||||
#
|
||||
# 用白名单打包,.env / node_modules / dist / .next 结构上不可能被传上去。
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
repo_root="$(dirname "$script_dir")"
|
||||
config_file="$script_dir/deploy.config.sh"
|
||||
|
||||
target='all'
|
||||
dry_run=0
|
||||
with_install=0
|
||||
|
||||
# bash 3.2(macOS 自带)在 set -u 下对无参数的 "$@" 会报 unbound variable,所以要加这层保护
|
||||
for arg in ${@+"$@"}; do
|
||||
case "$arg" in
|
||||
api|admin|all) target="$arg" ;;
|
||||
-n|--dry-run) dry_run=1 ;;
|
||||
--with-install) with_install=1 ;;
|
||||
-h|--help) sed -n '2,13p' "$0"; exit 0 ;;
|
||||
# ${arg} 必须带花括号:紧跟中文时 bash 会把多字节字符合进变量名
|
||||
*) echo "未知参数:${arg}(可用:api | admin | all | --dry-run | --with-install)" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -f "$config_file" ]; then
|
||||
echo 'ERROR: 找不到 deploy.config.sh' >&2
|
||||
echo '把 deploy/deploy.config.example.sh 复制成 deploy/deploy.config.sh,填好服务器信息再跑。' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
. "$config_file"
|
||||
|
||||
for cmd in ssh scp tar; do
|
||||
command -v "$cmd" >/dev/null 2>&1 || { echo "缺少命令:$cmd" >&2; exit 1; }
|
||||
done
|
||||
|
||||
ssh_target="$DEPLOY_USER@$DEPLOY_HOST"
|
||||
|
||||
# 读配置里的某一项,如 val API_LABEL
|
||||
val() {
|
||||
local out
|
||||
eval "out=\${$1:-}"
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
deploy_app() {
|
||||
local key="$1"
|
||||
local up label local_path remote_path paths excludes clean local_build
|
||||
local install build restart start health nginx_cache nginx_bin
|
||||
up="$(printf '%s' "$key" | tr '[:lower:]' '[:upper:]')"
|
||||
|
||||
label="$(val "${up}_LABEL")"
|
||||
local_path="$repo_root/$(val "${up}_LOCAL")"
|
||||
remote_path="$(val "${up}_REMOTE")"
|
||||
paths="$(val "${up}_PATHS")"
|
||||
excludes="$(val "${up}_EXCLUDES")"
|
||||
clean="$(val "${up}_CLEAN")"
|
||||
local_build="$(val "${up}_LOCAL_BUILD")"
|
||||
install="$(val "${up}_INSTALL")"
|
||||
build="$(val "${up}_BUILD")"
|
||||
restart="$(val "${up}_RESTART")"
|
||||
start="$(val "${up}_START")"
|
||||
health="$(val "${up}_HEALTH")"
|
||||
|
||||
[ -d "$local_path" ] || { echo "本地目录不存在:$local_path" >&2; exit 1; }
|
||||
|
||||
echo ''
|
||||
echo "=== $label ==="
|
||||
|
||||
# ---- 本地构建(默认关,配了 $X_LOCAL_BUILD 才跑)----
|
||||
if [ -n "$local_build" ]; then
|
||||
echo "[1/5] Building locally: $local_build"
|
||||
# 国内拉 Prisma 引擎很慢,指向镜像
|
||||
( cd "$local_path" && PRISMA_ENGINES_MIRROR='https://registry.npmmirror.com/-/binary/prisma' bash -c "$local_build" )
|
||||
else
|
||||
echo '[1/5] Skipping local build'
|
||||
fi
|
||||
|
||||
# ---- 打包:只收白名单里存在的路径 ----
|
||||
echo "[2/5] Packing $(val "${up}_LOCAL")"
|
||||
local stamp tar_file remote_tar items
|
||||
stamp="$(date +%Y%m%d-%H%M%S)"
|
||||
tar_file="${TMPDIR:-/tmp}/yelay-${key}-${stamp}.tar.gz"
|
||||
remote_tar="/tmp/$(basename "$tar_file")"
|
||||
|
||||
local -a tar_args=()
|
||||
for p in $excludes; do tar_args+=("--exclude=$p"); done
|
||||
local -a file_args=()
|
||||
for p in $paths; do
|
||||
[ -e "$local_path/$p" ] && file_args+=("$p")
|
||||
done
|
||||
[ ${#file_args[@]} -gt 0 ] || { echo "白名单里没有任何存在的路径:$paths" >&2; exit 1; }
|
||||
|
||||
( cd "$local_path" && tar -czf "$tar_file" ${tar_args[@]+"${tar_args[@]}"} "${file_args[@]}" )
|
||||
|
||||
local size_kb
|
||||
size_kb=$(( $(wc -c < "$tar_file") / 1024 ))
|
||||
echo " ${size_kb} KB ($(printf '%s, ' "${file_args[@]}" | sed 's/, $//'))"
|
||||
|
||||
if [ "$dry_run" = 1 ]; then
|
||||
echo ' DryRun: nothing uploaded.'
|
||||
rm -f "$tar_file"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "[3/5] Uploading to $remote_path"
|
||||
scp -P "$DEPLOY_PORT" -q "$tar_file" "$ssh_target:$remote_tar"
|
||||
|
||||
# ---- 拼远端脚本 ----
|
||||
local clean_cmd=''
|
||||
for p in $clean; do clean_cmd="$clean_cmd
|
||||
rm -rf '$remote_path/$p'"; done
|
||||
|
||||
local install_cmd=''
|
||||
[ "$with_install" = 1 ] && install_cmd="$install"
|
||||
|
||||
local start_cmd=''
|
||||
# 先 sleep 2 让刚被杀的进程彻底放开端口,否则新进程会 EADDRINUSE
|
||||
[ -n "$start" ] && start_cmd="sleep 2
|
||||
$start"
|
||||
|
||||
# 探活:30 秒还没起来就让部署直接失败,免得「显示成功、线上 502」
|
||||
local health_cmd=''
|
||||
if [ -n "$health" ]; then
|
||||
health_cmd="for i in {1..30}; do curl -sf -o /dev/null '$health' && break; sleep 1; done
|
||||
curl -sf -o /dev/null '$health' || { echo 'ERROR: service did not come up: $health'; exit 1; }"
|
||||
fi
|
||||
|
||||
nginx_cache="$(val NGINX_CACHE_DIR)"
|
||||
nginx_bin="$(val NGINX_BIN)"
|
||||
local nginx_cmd=''
|
||||
if [ -n "$nginx_cache" ]; then
|
||||
nginx_cmd="find '$nginx_cache' -mindepth 1 -delete 2>/dev/null || true"
|
||||
[ -n "$nginx_bin" ] && nginx_cmd="$nginx_cmd
|
||||
'$nginx_bin' -s reload 2>/dev/null || true"
|
||||
fi
|
||||
|
||||
# 远端脚本保持 ASCII 注释,避免 SSH 传输编码问题
|
||||
local remote_script
|
||||
remote_script="$(cat <<REMOTE
|
||||
set -e
|
||||
export PATH=${NODE_BIN}:\$PATH
|
||||
mkdir -p '$remote_path'
|
||||
cd '$remote_path'
|
||||
$clean_cmd
|
||||
# macOS 打的包带 com.apple.provenance 之类的 xattr 头,GNU tar 每条警告一行,刷屏且无用
|
||||
tar --warning=no-unknown-keyword -xzf '$remote_tar'
|
||||
rm -f '$remote_tar'
|
||||
$install_cmd
|
||||
$build
|
||||
$restart
|
||||
$start_cmd
|
||||
$health_cmd
|
||||
$nginx_cmd
|
||||
echo '__DEPLOY_DONE__'
|
||||
REMOTE
|
||||
)"
|
||||
|
||||
echo '[4/5] Running on server'
|
||||
ssh -p "$DEPLOY_PORT" "$ssh_target" 'bash -s' <<< "$remote_script"
|
||||
|
||||
rm -f "$tar_file"
|
||||
|
||||
if [ -n "$restart" ]; then
|
||||
echo '[5/5] Restarted'
|
||||
else
|
||||
echo '[5/5] Done'
|
||||
echo " NOTE: 去宝塔面板手动重启 $label"
|
||||
fi
|
||||
[ -n "$start" ] && echo " Started, health check passed: $health"
|
||||
[ -n "$nginx_cmd" ] && echo ' Nginx proxy cache cleared and reloaded'
|
||||
}
|
||||
|
||||
started_at=$(date +%s)
|
||||
case "$target" in
|
||||
api) deploy_app api ;;
|
||||
admin) deploy_app admin ;;
|
||||
all) deploy_app api; deploy_app admin ;;
|
||||
esac
|
||||
|
||||
[ "$dry_run" = 1 ] || echo "
|
||||
All done in $(( $(date +%s) - started_at ))s"
|
||||
Reference in new issue
Block a user