200 lines
7.0 KiB
YAML
200 lines
7.0 KiB
YAML
name: Deploy Frontend via Git
|
||
|
||
# 触发条件
|
||
on:
|
||
# 当推送到主分支且修改前端相关文件时自动触发
|
||
push:
|
||
branches: [ main ]
|
||
paths:
|
||
- 'frontend/**'
|
||
- '.github/workflows/deploy_frontend.git.yml'
|
||
# 支持手动触发
|
||
workflow_dispatch:
|
||
|
||
jobs:
|
||
build-and-deploy:
|
||
runs-on: ubuntu-latest
|
||
|
||
steps:
|
||
# 检出代码
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
# 设置Node.js环境
|
||
- name: Set up Node.js
|
||
uses: actions/setup-node@v4
|
||
with:
|
||
node-version: '18'
|
||
|
||
# 设置pnpm
|
||
- name: Set up pnpm
|
||
uses: pnpm/action-setup@v4
|
||
with:
|
||
version: 10
|
||
run_install: false
|
||
|
||
# 缓存node_modules(不缓存构建输出,确保每次都是最新构建)
|
||
- name: Cache dependencies
|
||
uses: actions/cache@v4
|
||
with:
|
||
path: |
|
||
frontend/node_modules
|
||
~/.pnpm-store
|
||
key: ${{ runner.os }}-frontend-deps-${{ hashFiles('frontend/pnpm-lock.yaml') }}
|
||
restore-keys: |
|
||
${{ runner.os }}-frontend-deps-
|
||
|
||
# 安装依赖
|
||
- name: Install dependencies
|
||
run: |
|
||
cd frontend
|
||
pnpm install --frozen-lockfile
|
||
|
||
# 清理旧的构建目录(确保使用最新代码构建)
|
||
- name: Clean old build artifacts
|
||
run: |
|
||
cd frontend
|
||
rm -rf production dist
|
||
echo "Cleaned old build directories"
|
||
|
||
# 执行类型检查和构建
|
||
- name: Type check and build
|
||
run: |
|
||
cd frontend
|
||
# 设置构建环境变量,确保与本地构建一致
|
||
export VITE_OUTDIR=production
|
||
export VITE_ADDRESS_BASE_URL=/production/
|
||
# 先执行类型检查
|
||
pnpm run type-check
|
||
# 然后执行构建
|
||
pnpm run build:prod
|
||
# 检查构建结果
|
||
echo "Build completed, checking production directory:"
|
||
ls -la production/
|
||
# 验证构建产物中的 base 路径
|
||
echo "Verifying base path in index.html:"
|
||
grep -o 'href="/production/' production/index.html | head -1 || echo "Warning: base path not found"
|
||
# 显示构建产物的时间戳,确认是新构建的
|
||
echo "Build timestamp:"
|
||
stat production/index.html 2>/dev/null || ls -la production/index.html
|
||
|
||
# 准备临时部署目录
|
||
- name: Prepare temp directory
|
||
uses: appleboy/ssh-action@v1.0.3
|
||
with:
|
||
host: ${{ secrets.HOST43 }}
|
||
username: root
|
||
password: ${{ secrets.PASS43 }}
|
||
port: 22
|
||
script: |
|
||
sudo rm -rf /home/pi/lm-www/frontend_tmp
|
||
sudo mkdir -p /home/pi/lm-www/frontend_tmp/production
|
||
sudo chown -R root:root /home/pi/lm-www/frontend_tmp
|
||
|
||
# 安装 rsync(用于带进度显示的文件传输)
|
||
- name: Install rsync
|
||
run: sudo apt-get update && sudo apt-get install -y rsync sshpass
|
||
|
||
# 计算要传输的文件总大小
|
||
- name: Calculate total size
|
||
id: calc_size
|
||
run: |
|
||
cd frontend/production
|
||
TOTAL_SIZE=$(du -sb . | cut -f1)
|
||
echo "total_size=$TOTAL_SIZE" >> $GITHUB_OUTPUT
|
||
echo "Total size to transfer: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE)"
|
||
|
||
# 将构建产物传输到服务器(带进度显示)
|
||
- name: Copy build files to server with progress
|
||
run: |
|
||
set -e
|
||
echo "Starting file transfer with rsync..."
|
||
|
||
# 启动后台传输(使用 --info=progress2 只显示总体进度,减少输出)
|
||
sshpass -p "${{ secrets.PASS43 }}" rsync -avz --info=progress2 \
|
||
-e "ssh -o StrictHostKeyChecking=no" \
|
||
frontend/production/ \
|
||
root@${{ secrets.HOST43 }}:/home/pi/lm-www/frontend_tmp/production/ > /tmp/rsync.log 2>&1 &
|
||
RSYNC_PID=$!
|
||
|
||
# 每10秒显示一次进度
|
||
TOTAL_SIZE=${{ steps.calc_size.outputs.total_size }}
|
||
echo "📦 Total size: $(numfmt --to=iec-i --suffix=B $TOTAL_SIZE 2>/dev/null || echo "${TOTAL_SIZE}B")"
|
||
|
||
while kill -0 $RSYNC_PID 2>/dev/null; do
|
||
sleep 10
|
||
# 通过SSH检查目标目录大小
|
||
TRANSFERRED=$(sshpass -p "${{ secrets.PASS43 }}" ssh -o StrictHostKeyChecking=no \
|
||
root@${{ secrets.HOST43 }} \
|
||
"du -sb /home/pi/lm-www/frontend_tmp/production 2>/dev/null | cut -f1" || echo "0")
|
||
|
||
if [ "$TRANSFERRED" != "0" ] && [ "$TOTAL_SIZE" != "0" ]; then
|
||
PERCENT=$((TRANSFERRED * 100 / TOTAL_SIZE))
|
||
TRANSFERRED_HR=$(numfmt --to=iec-i --suffix=B $TRANSFERRED 2>/dev/null || echo "${TRANSFERRED}B")
|
||
TOTAL_HR=$(numfmt --to=iec-i --suffix=B $TOTAL_SIZE 2>/dev/null || echo "${TOTAL_SIZE}B")
|
||
echo "📦 Transfer progress: $PERCENT% ($TRANSFERRED_HR / $TOTAL_HR)"
|
||
else
|
||
echo "📦 Transfer in progress..."
|
||
fi
|
||
done
|
||
|
||
# 等待传输完成并检查退出码
|
||
wait $RSYNC_PID
|
||
EXIT_CODE=$?
|
||
|
||
# 显示 rsync 的最后几行输出
|
||
echo "--- rsync output (last 20 lines) ---"
|
||
tail -20 /tmp/rsync.log || true
|
||
|
||
if [ $EXIT_CODE -eq 0 ]; then
|
||
echo "✅ File transfer completed!"
|
||
else
|
||
echo "❌ File transfer failed with exit code $EXIT_CODE"
|
||
exit $EXIT_CODE
|
||
fi
|
||
env:
|
||
DEBIAN_FRONTEND: noninteractive
|
||
|
||
# 完成部署:直接替换并重启 nginx
|
||
- name: Deploy to production
|
||
uses: appleboy/ssh-action@v1.0.3
|
||
with:
|
||
host: ${{ secrets.HOST43 }}
|
||
username: root
|
||
password: ${{ secrets.PASS43 }}
|
||
port: 22
|
||
script: |
|
||
set -e
|
||
|
||
echo "Deploying to production..."
|
||
# 确保 frontend 目录存在
|
||
sudo mkdir -p /home/pi/lm-www/frontend
|
||
# 删除原有的 production 目录
|
||
sudo rm -rf /home/pi/lm-www/frontend/production
|
||
# 将新的 production 目录移过去
|
||
sudo mv /home/pi/lm-www/frontend_tmp/production /home/pi/lm-www/frontend/production
|
||
# 清理临时目录
|
||
sudo rm -rf /home/pi/lm-www/frontend_tmp
|
||
|
||
echo "Setting permissions..."
|
||
# 将前端目录权限授予 nginx 运行用户(OpenCloudOS 上通常为 nginx)
|
||
sudo chown -R nginx:nginx /home/pi/lm-www/frontend/
|
||
sudo chmod -R 644 /home/pi/lm-www/frontend/
|
||
sudo find /home/pi/lm-www/frontend/ -type d -exec chmod 755 {} \;
|
||
|
||
echo "Verifying deployment structure..."
|
||
ls -la /home/pi/lm-www/frontend/
|
||
ls -la /home/pi/lm-www/frontend/production/ || echo "Warning: production directory not found"
|
||
|
||
echo "Reloading nginx..."
|
||
# 与服务器手动操作保持一致:先测试配置,再重载
|
||
if command -v nginx >/dev/null 2>&1; then
|
||
echo "Testing nginx config (nginx -t)..."
|
||
sudo nginx -t
|
||
echo "Reloading nginx (nginx -s reload)..."
|
||
sudo nginx -s reload
|
||
else
|
||
echo "⚠️ 未找到 nginx 命令,请确认 nginx 是否已安装并在 PATH 中"
|
||
fi
|
||
|
||
echo "✅ Deployment completed!" |