ci: 归档 ECS 专用工作流;新增 NAS 自动部署流水线

This commit is contained in:
2026-10-10 16:33:29 +08:00
parent 0593ff7e62
commit a41a6644a4
17 changed files with 45 additions and 0 deletions
+98
View File
@@ -0,0 +1,98 @@
name: Deploy Web to ECS
# 数字我前端(纯成人版)
on:
workflow_dispatch: {} # ★ 允许在 Actions 页面手动触发部署(老板要求 2026-07-28)
push:
# ⚠ 只监听 master。原来 [master, main] 是一把上膛的枪:
# main 是落后 169 个提交的僵尸分支,往它推任何一行代码,
# 都会把旧代码盖到生产上。(已发生过一次。main 现已删除。)
branches: [master]
paths:
- 'digital-me-web/**'
- '.github/workflows/deploy-adult-web.yml'
# ★ 并发锁:同一时刻只跑一个前端部署,多次快连推【串行、不重叠】。
# 2026-07-20 事故:连推三次(80ed3f8/379b671/ed91b14)三个部署乱序上传 chunk,
# 服务器一度新旧混装,懒加载的天下几章刷到「新 index.html 配已删旧 chunk」→ 打不开。
# cancel-in-progress: false ⇒ 不中途掐(scp/rsync 掐一半更糟),排队跑完;
# GitHub 会把中间那个 pending 顶掉,最终落定的永远是最新一次 push 的构建。
concurrency:
group: deploy-adult-web
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
defaults:
run:
working-directory: digital-me-web
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: digital-me-web/package-lock.json
- run: npm ci
- run: npm run build:fast
env:
VITE_API_BASE_URL: https://digitalme-api.invoratec.cn
- name: Upload dist to staging
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ secrets.ECS_HOST }}
username: ${{ secrets.ECS_USER }}
password: ${{ secrets.ECS_PASSWORD }}
source: 'digital-me-web/dist/*'
target: /tmp/dm-web-dist
strip_components: 2
overwrite: true
- name: Publish to nginx root + reload
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.ECS_HOST }}
username: ${{ secrets.ECS_USER }}
password: ${{ secrets.ECS_PASSWORD }}
script: |
# ★★ 2026-07-28:写死本站 SPA 目录,【绝不】扫描 nginx root、【绝不】按 index.html 内容猜目录。
# 起因:同源同品牌(数字我家族)多站同服务器时,按 "index.html 含 数字我" 猜目录,会把隔壁
# superdigitme("超级数字我")的前端一起覆盖(2026-07-28 事故)。数字我(成人)前端唯一落点就是这里。
# 要改路径,只改这一行 ROOT。
ROOT=/var/www/digitalme-spa
RESOLVE="--resolve digitalme.invoratec.cn:443:127.0.0.1"
NEW=$(grep -oE 'index-[A-Za-z0-9_-]+\.js' /tmp/dm-web-dist/index.html 2>/dev/null | head -1)
if [ -z "$NEW" ]; then echo "::error::上传的 dist 里没有 index.html——上传步骤有问题,中止,不写盘。"; exit 1; fi
mkdir -p "$ROOT"
cp -rf /tmp/dm-web-dist/* "$ROOT"/
WROTE="$ROOT"
echo "✓ 已写入固定目录 $ROOT (指纹 $NEW)"
rm -rf /tmp/dm-web-dist
# 清理上一次误传进 acme 目录的 SPA 文件(不动真正的 challenge 文件)。
rm -rf /var/www/acme-challenge/assets /var/www/acme-challenge/index.html 2>/dev/null || true
# ── 缓存头(幂等【替换】,不再跳过): index.html 改 no-store —— 浏览器永不缓存首页,每次强制拿最新,
# 根治「老用户/旧标签页一直加载旧 bundle、看不到新版」(no-cache 会被 bfcache 绕过,no-store 不会)。
# hash 资源仍长缓存(immutable)。带 nginx -t 校验, 失败即回滚。 ──
CONF=/etc/nginx/conf.d/digitalme.invoratec.cn.conf
if [ -f "$CONF" ]; then
cp "$CONF" "$CONF.dmbak"
sed -i '/# dm-cache-headers/d' "$CONF" # 先删旧头(如有), 再注入新的
sed -i '/index index\.html;/a location = /index.html { add_header Cache-Control "no-store, no-cache, must-revalidate"; } location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; } # dm-cache-headers' "$CONF"
if nginx -t 2>/dev/null; then echo "✓ nginx 缓存头已更新(index.html=no-store)"; else echo "❌ nginx -t 失败, 已回滚缓存头"; cp "$CONF.dmbak" "$CONF"; fi
else
echo "✓ conf 缺失, 跳过缓存头"
fi
nginx -s reload 2>/dev/null || true
sleep 2
# ★★ 发布后自检:以【公网真实 URL】(老板看到的那个)为准;不一致就把整张诊断表写进红色 ::error:: 标注
# ——GitHub 会把它显示在运行页顶部(就是老板一直能看到、能贴回来的那种),这样病根直接暴露、不用再猜。
LOCAL=$(curl -sk $RESOLVE https://digitalme.invoratec.cn/ 2>/dev/null | grep -oE 'index-[A-Za-z0-9_-]+\.js' | head -1)
PUB=$(curl -s "https://digitalme.invoratec.cn/?cc=$$" 2>/dev/null | grep -oE 'index-[A-Za-z0-9_-]+\.js' | head -1)
echo "=== 发布后自检 === 应发布=$NEW 本机served=$LOCAL 公网served=$PUB 写入目录=[$WROTE]"
if [ "$NEW" != "$PUB" ]; then
echo "::error::已写入 $WROTE 并 reload,但公网仍非最新。应发=$NEW 本机=$LOCAL 公网=$PUB。请确认 digitalme.invoratec.cn 的 nginx root 是否为 $WROTE。"
exit 1
fi
echo "✓✓ 自检通过:公网已是最新 $NEW"