|
1 | 1 | #!/usr/bin/env bash |
2 | 2 | # Zap 官网部署脚本(在服务器上执行) |
3 | 3 | # |
4 | | -# 由 GitHub Actions 上传到 $DEPLOY_PATH/deploy/deploy.sh 后,经 chmod +x 远程执行。 |
5 | | -# 职责:把上传好的静态产物(dist/)切换为对外服务目录,做原子发布 + 保留回滚。 |
| 4 | +# 场景:站点由 1Panel 托管,nginx root 固定指向站点目录(例如 |
| 5 | +# /opt/1panel/www/sites/zap.zerx.dev/index),无法改 root 用 symlink 方案。 |
| 6 | +# 故这里做"原子目录替换":CI 已把最新产物 rsync 到 <site>/.incoming, |
| 7 | +# 本脚本把 .incoming 重命名为正式 index 目录,并保留上一版用于回滚。 |
6 | 8 | # |
7 | | -# 约定的目录布局($DEPLOY_PATH 下): |
8 | | -# incoming/ ← Actions 用 rsync 推上来的最新 dist 内容 |
9 | | -# releases/<ts>/ ← 每次发布的快照 |
10 | | -# current ← symlink,指向当前生效的 releases/<ts>(nginx root 指这里) |
11 | | -# |
12 | | -# nginx 的 root 应配置为 $DEPLOY_PATH/current |
| 9 | +# 约定布局($DEPLOY_PATH = 站点 index 目录,例如 .../zap.zerx.dev/index): |
| 10 | +# <parent>/.incoming ← CI rsync 推上来的最新 dist 内容 |
| 11 | +# <parent>/index ← nginx 实际服务的目录(= $DEPLOY_PATH) |
| 12 | +# <parent>/.index.bak ← 上一版,用于回滚 |
13 | 13 | set -euo pipefail |
14 | 14 |
|
15 | | -# 部署根目录:脚本位于 <root>/deploy/deploy.sh,故根目录是脚本上两级 |
16 | | -ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
17 | | -INCOMING="$ROOT/incoming" |
18 | | -RELEASES="$ROOT/releases" |
19 | | -CURRENT="$ROOT/current" |
20 | | -KEEP=5 # 保留最近多少份 release 用于回滚 |
| 15 | +# $DEPLOY_PATH 由调用方(SSH 命令)以第一个参数传入,即正式 index 目录 |
| 16 | +INDEX="${1:?用法: deploy.sh <site-index-dir>}" |
| 17 | +PARENT="$(dirname "$INDEX")" |
| 18 | +INCOMING="$PARENT/.incoming" |
| 19 | +BACKUP="$PARENT/.index.bak" |
21 | 20 |
|
22 | 21 | log() { printf '[deploy] %s\n' "$*"; } |
23 | 22 |
|
24 | 23 | if [ ! -d "$INCOMING" ] || [ -z "$(ls -A "$INCOMING" 2>/dev/null)" ]; then |
25 | | - log "错误:$INCOMING 不存在或为空,没有可发布的产物。先由 CI rsync 产物到 incoming/。" |
| 24 | + log "错误:$INCOMING 不存在或为空,没有可发布的产物(先由 CI rsync 到 .incoming)。" |
26 | 25 | exit 1 |
27 | 26 | fi |
28 | 27 |
|
29 | | -TS="$(date +%Y%m%d%H%M%S)" |
30 | | -TARGET="$RELEASES/$TS" |
31 | | - |
32 | | -mkdir -p "$RELEASES" |
33 | | -log "创建发布快照:$TARGET" |
34 | | -# 用 cp -a 从 incoming 物化一份不可变快照,保证 current 切换是原子的 |
35 | | -cp -a "$INCOMING" "$TARGET" |
36 | | - |
37 | | -# 原子切换 current symlink:先建临时 link 再 rename,避免出现短暂无 current 的窗口 |
38 | | -log "切换 current -> releases/$TS" |
39 | | -ln -sfn "$TARGET" "$CURRENT.tmp" |
40 | | -mv -Tf "$CURRENT.tmp" "$CURRENT" |
| 28 | +# 删除上一版备份,把当前 index 移为备份(若存在) |
| 29 | +if [ -e "$INDEX" ]; then |
| 30 | + log "备份当前版本 -> $BACKUP" |
| 31 | + rm -rf "$BACKUP" |
| 32 | + mv -Tf "$INDEX" "$BACKUP" |
| 33 | +fi |
41 | 34 |
|
42 | | -# 清理旧 release,保留最近 $KEEP 份 |
43 | | -log "清理旧 release,保留最近 $KEEP 份" |
44 | | -cd "$RELEASES" |
45 | | -ls -1dt */ 2>/dev/null | tail -n +$((KEEP + 1)) | while read -r old; do |
46 | | - log " 删除 $old" |
47 | | - rm -rf "${RELEASES:?}/${old%/}" |
48 | | -done |
| 35 | +# 原子上线:rename .incoming -> index(同一文件系统,mv 为原子操作) |
| 36 | +log "发布新版本 -> $INDEX" |
| 37 | +mv -Tf "$INCOMING" "$INDEX" |
49 | 38 |
|
50 | | -log "完成。current 现指向:$(readlink -f "$CURRENT")" |
| 39 | +log "完成。当前服务目录:$INDEX" |
| 40 | +log "如需回滚:rm -rf '$INDEX' && mv -Tf '$BACKUP' '$INDEX'" |
0 commit comments