Compare commits
5 Commits
618ac0bf8c
..
cicd
| Author | SHA1 | Date | |
|---|---|---|---|
| bd4091524e | |||
| 5b7f778551 | |||
| 38f64f770d | |||
| 2ee249f6f7 | |||
| e3698a8a60 |
+195
-67
@@ -37,7 +37,36 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: https://gitea.cn/actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: 缓存服务健康检查
|
||||||
|
id: cache-health
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
echo "检查缓存服务可用性..."
|
||||||
|
|
||||||
|
# 设置缓存可用性标志
|
||||||
|
CACHE_AVAILABLE=true
|
||||||
|
|
||||||
|
# 测试GitHub Actions缓存API
|
||||||
|
if ! curl -s --connect-timeout 10 --max-time 30 "https://api.github.com/repos/${{ github.repository }}/actions/caches" > /dev/null 2>&1; then
|
||||||
|
echo "⚠️ GitHub Actions缓存服务不可用,将跳过缓存步骤"
|
||||||
|
CACHE_AVAILABLE=false
|
||||||
|
else
|
||||||
|
echo "✅ 缓存服务可用"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "CACHE_AVAILABLE=$CACHE_AVAILABLE" >> $GITHUB_ENV
|
||||||
|
echo "cache-available=$CACHE_AVAILABLE" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: 缓存降级提示
|
||||||
|
if: env.CACHE_AVAILABLE == 'false'
|
||||||
|
run: |
|
||||||
|
echo "🔄 缓存服务不可用,构建将在无缓存模式下进行"
|
||||||
|
echo "⏱️ 这可能会增加构建时间,但不会影响构建结果"
|
||||||
|
echo "📦 所有依赖将重新下载和安装"
|
||||||
|
|
||||||
- name: Install system tools (jq, docker, curl)
|
- name: Install system tools (jq, docker, curl)
|
||||||
run: |
|
run: |
|
||||||
@@ -122,7 +151,9 @@ jobs:
|
|||||||
echo "canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas" >> .npmrc
|
echo "canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas" >> .npmrc
|
||||||
|
|
||||||
- name: Install dependencies cache (Bun)
|
- name: Install dependencies cache (Bun)
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: ~/.bun
|
path: ~/.bun
|
||||||
key: bun-${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('bun.lock') }}
|
key: bun-${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('bun.lock') }}
|
||||||
@@ -131,7 +162,9 @@ jobs:
|
|||||||
bun-${{ runner.os }}-
|
bun-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Install dependencies cache (node_modules)
|
- name: Install dependencies cache (node_modules)
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
node_modules
|
node_modules
|
||||||
@@ -175,11 +208,15 @@ jobs:
|
|||||||
echo "✅ 缓存目录已准备完成"
|
echo "✅ 缓存目录已准备完成"
|
||||||
|
|
||||||
- name: Turborepo cache (.turbo)
|
- name: Turborepo cache (.turbo)
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: .turbo
|
path: .turbo
|
||||||
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('bun.lock') }}
|
key: turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('apps/**/package.json') }}-${{ hashFiles('packages/**/package.json') }}-${{ hashFiles('bun.lock') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
|
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('apps/**/package.json') }}-${{ hashFiles('packages/**/package.json') }}-
|
||||||
|
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-
|
||||||
turbo-${{ runner.os }}-
|
turbo-${{ runner.os }}-
|
||||||
|
|
||||||
- name: 安装依赖 (bun)
|
- name: 安装依赖 (bun)
|
||||||
@@ -269,7 +306,9 @@ jobs:
|
|||||||
echo "BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
|
echo "BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Cache Next.js build artifacts (.next/cache)
|
- name: Cache Next.js build artifacts (.next/cache)
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
apps/admin/.next/cache
|
apps/admin/.next/cache
|
||||||
@@ -280,7 +319,9 @@ jobs:
|
|||||||
nextcache-${{ runner.os }}-
|
nextcache-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Cache build outputs
|
- name: Cache build outputs
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
apps/admin/.next
|
apps/admin/.next
|
||||||
@@ -293,7 +334,9 @@ jobs:
|
|||||||
build-${{ runner.os }}-
|
build-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Cache ESLint
|
- name: Cache ESLint
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
.eslintcache
|
.eslintcache
|
||||||
@@ -304,7 +347,9 @@ jobs:
|
|||||||
eslint-${{ runner.os }}-
|
eslint-${{ runner.os }}-
|
||||||
|
|
||||||
- name: Cache TypeScript
|
- name: Cache TypeScript
|
||||||
uses: https://gitea.cn/actions/cache@v3
|
if: env.CACHE_AVAILABLE == 'true'
|
||||||
|
uses: actions/cache@v4
|
||||||
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
path: |
|
path: |
|
||||||
.tsbuildinfo
|
.tsbuildinfo
|
||||||
@@ -359,16 +404,34 @@ jobs:
|
|||||||
docker push ${{ env.DOCKER_REGISTRY }}/ppanel/ppanel-user-web:${{ env.VERSION }}
|
docker push ${{ env.DOCKER_REGISTRY }}/ppanel/ppanel-user-web:${{ env.VERSION }}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: SSH连接预检查
|
||||||
|
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
|
||||||
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
|
with:
|
||||||
|
host: ${{ env.SSH_HOST }}
|
||||||
|
username: ${{ env.SSH_USER }}
|
||||||
|
password: ${{ env.SSH_PASSWORD }}
|
||||||
|
port: ${{ env.SSH_PORT }}
|
||||||
|
timeout: 300s
|
||||||
|
command_timeout: 600s
|
||||||
|
debug: true
|
||||||
|
script: |
|
||||||
|
echo "=== SSH连接测试 ==="
|
||||||
|
echo "连接时间: $(date)"
|
||||||
|
echo "服务器主机名: $(hostname)"
|
||||||
|
echo "当前用户: $(whoami)"
|
||||||
|
echo "系统信息: $(uname -a)"
|
||||||
|
echo "Docker版本: $(docker --version 2>/dev/null || echo 'Docker未安装')"
|
||||||
|
echo "✅ SSH连接成功"
|
||||||
|
|
||||||
- name: 部署管理面板到服务器
|
- name: 部署管理面板到服务器
|
||||||
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
|
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
with:
|
with:
|
||||||
host: ${{ secrets.HOST }}
|
host: ${{ env.SSH_HOST }}
|
||||||
username: ${{ secrets.USERNAME }}
|
username: ${{ env.SSH_USER }}
|
||||||
key: ${{ secrets.KEY }}
|
password: ${{ env.SSH_PASSWORD }}
|
||||||
port: ${{ secrets.PORT }}
|
port: ${{ env.SSH_PORT }}
|
||||||
timeout: 300s
|
timeout: 300s
|
||||||
command_timeout: 600s
|
command_timeout: 600s
|
||||||
script: |
|
script: |
|
||||||
@@ -435,24 +498,53 @@ jobs:
|
|||||||
|
|
||||||
# 安全停止和移除容器
|
# 安全停止和移除容器
|
||||||
echo "检查现有容器状态..."
|
echo "检查现有容器状态..."
|
||||||
if docker ps -q -f name=ppanel-admin-web | grep -q .; then
|
CONTAINER_NAME="ppanel-admin-web"
|
||||||
|
|
||||||
|
# 检查容器是否存在
|
||||||
|
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
|
||||||
|
echo "发现现有容器,开始清理..."
|
||||||
|
|
||||||
|
# 检查容器是否正在运行
|
||||||
|
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
|
||||||
echo "停止运行中的容器..."
|
echo "停止运行中的容器..."
|
||||||
docker stop ppanel-admin-web --time=10 || true
|
docker stop $CONTAINER_NAME --time=15 || true
|
||||||
sleep 3
|
sleep 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if docker ps -aq -f name=ppanel-admin-web | grep -q .; then
|
# 检查容器是否正在被移除
|
||||||
echo "移除现有容器..."
|
echo "检查容器移除状态..."
|
||||||
# 等待容器完全停止
|
for i in {1..15}; do
|
||||||
for i in {1..10}; do
|
# 尝试获取容器状态
|
||||||
if docker rm ppanel-admin-web 2>/dev/null; then
|
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
|
||||||
echo "容器移除成功"
|
|
||||||
|
if [ "$CONTAINER_STATUS" = "not_found" ]; then
|
||||||
|
echo "✅ 容器已不存在"
|
||||||
|
break
|
||||||
|
elif [ "$CONTAINER_STATUS" = "removing" ]; then
|
||||||
|
echo "⏳ 容器正在移除中,等待完成... $i/15"
|
||||||
|
sleep 3
|
||||||
|
else
|
||||||
|
echo "尝试移除容器... $i/15"
|
||||||
|
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
|
||||||
|
echo "✅ 容器移除成功"
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
echo "等待容器停止... $i/10"
|
echo "⚠️ 容器移除失败,重试..."
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 最后一次尝试强制清理
|
||||||
|
if [ $i -eq 15 ]; then
|
||||||
|
echo "🔧 执行强制清理..."
|
||||||
|
docker kill $CONTAINER_NAME 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
docker rm -f $CONTAINER_NAME 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
else
|
||||||
|
echo "✅ 未发现现有容器"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "启动新容器..."
|
echo "启动新容器..."
|
||||||
@@ -484,12 +576,13 @@ jobs:
|
|||||||
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
|
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
|
||||||
uses: appleboy/ssh-action@v1.0.3
|
uses: appleboy/ssh-action@v1.0.3
|
||||||
with:
|
with:
|
||||||
host: ${{ secrets.HOST }}
|
host: ${{ env.SSH_HOST }}
|
||||||
username: ${{ secrets.USERNAME }}
|
username: ${{ env.SSH_USER }}
|
||||||
key: ${{ secrets.KEY }}
|
password: ${{ env.SSH_PASSWORD }}
|
||||||
port: ${{ secrets.PORT }}
|
port: ${{ env.SSH_PORT }}
|
||||||
timeout: 300s
|
timeout: 300s
|
||||||
command_timeout: 600s
|
command_timeout: 600s
|
||||||
|
debug: true
|
||||||
script: |
|
script: |
|
||||||
echo "=== SSH变量调试信息 ==="
|
echo "=== SSH变量调试信息 ==="
|
||||||
echo "DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }}"
|
echo "DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }}"
|
||||||
@@ -554,24 +647,53 @@ jobs:
|
|||||||
|
|
||||||
# 安全停止和移除容器
|
# 安全停止和移除容器
|
||||||
echo "检查现有容器状态..."
|
echo "检查现有容器状态..."
|
||||||
if docker ps -q -f name=ppanel-user-web | grep -q .; then
|
CONTAINER_NAME="ppanel-user-web"
|
||||||
|
|
||||||
|
# 检查容器是否存在
|
||||||
|
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
|
||||||
|
echo "发现现有容器,开始清理..."
|
||||||
|
|
||||||
|
# 检查容器是否正在运行
|
||||||
|
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
|
||||||
echo "停止运行中的容器..."
|
echo "停止运行中的容器..."
|
||||||
docker stop ppanel-user-web --time=10 || true
|
docker stop $CONTAINER_NAME --time=15 || true
|
||||||
sleep 3
|
sleep 5
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if docker ps -aq -f name=ppanel-user-web | grep -q .; then
|
# 检查容器是否正在被移除
|
||||||
echo "移除现有容器..."
|
echo "检查容器移除状态..."
|
||||||
# 等待容器完全停止
|
for i in {1..15}; do
|
||||||
for i in {1..10}; do
|
# 尝试获取容器状态
|
||||||
if docker rm ppanel-user-web 2>/dev/null; then
|
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
|
||||||
echo "容器移除成功"
|
|
||||||
|
if [ "$CONTAINER_STATUS" = "not_found" ]; then
|
||||||
|
echo "✅ 容器已不存在"
|
||||||
|
break
|
||||||
|
elif [ "$CONTAINER_STATUS" = "removing" ]; then
|
||||||
|
echo "⏳ 容器正在移除中,等待完成... $i/15"
|
||||||
|
sleep 3
|
||||||
|
else
|
||||||
|
echo "尝试移除容器... $i/15"
|
||||||
|
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
|
||||||
|
echo "✅ 容器移除成功"
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
echo "等待容器停止... $i/10"
|
echo "⚠️ 容器移除失败,重试..."
|
||||||
|
sleep 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 最后一次尝试强制清理
|
||||||
|
if [ $i -eq 15 ]; then
|
||||||
|
echo "🔧 执行强制清理..."
|
||||||
|
docker kill $CONTAINER_NAME 2>/dev/null || true
|
||||||
|
sleep 2
|
||||||
|
docker rm -f $CONTAINER_NAME 2>/dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
else
|
||||||
|
echo "✅ 未发现现有容器"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "启动新容器..."
|
echo "启动新容器..."
|
||||||
@@ -599,39 +721,45 @@ jobs:
|
|||||||
docker logs ppanel-user-web || true
|
docker logs ppanel-user-web || true
|
||||||
exit 1
|
exit 1
|
||||||
|
|
||||||
- name: 发送成功通知到Telegram
|
# 步骤5: TG通知 (成功)
|
||||||
|
- name: 📱 发送成功通知到Telegram
|
||||||
if: success()
|
if: success()
|
||||||
run: |
|
uses: chapvic/telegram-notify@master
|
||||||
MESSAGE="✅ 部署成功!
|
with:
|
||||||
|
bot_token: ${{ env.TELEGRAM_BOT_TOKEN }}
|
||||||
|
chat_id: ${{ env.TELEGRAM_CHAT_ID }}
|
||||||
|
message: |
|
||||||
|
✅ **部署成功!**
|
||||||
|
|
||||||
📦 项目: ${{ github.repository }}
|
📦 **项目**: ${{ github.repository }}
|
||||||
🌿 分支: ${{ github.ref_name }}
|
🌿 **分支**: ${{ github.ref_name }}
|
||||||
🔖 版本: ${{ env.VERSION }}
|
🔖 **版本**: ${{ env.VERSION }}
|
||||||
🎯 构建目标: ${{ env.BUILD_TARGET }}
|
🎯 **构建目标**: ${{ env.BUILD_TARGET }}
|
||||||
🔗 API地址: ${{ env.NEXT_PUBLIC_API_URL }}
|
🔗 **API地址**: ${{ env.NEXT_PUBLIC_API_URL }}
|
||||||
|
📝 **提交**: ${{ github.sha }}
|
||||||
|
👤 **提交者**: ${{ github.actor }}
|
||||||
|
🕐 **时间**: ${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
🕐 时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
🚀 **服务已成功部署到生产环境**
|
||||||
|
parse_mode: Markdown
|
||||||
|
|
||||||
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
# 步骤5: TG通知 (失败)
|
||||||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
- name: 📱 发送失败通知到Telegram
|
||||||
-d text="$MESSAGE" \
|
|
||||||
-d parse_mode="HTML"
|
|
||||||
|
|
||||||
- name: 发送失败通知到Telegram
|
|
||||||
if: failure()
|
if: failure()
|
||||||
run: |
|
uses: chapvic/telegram-notify@master
|
||||||
MESSAGE="❌ 部署失败!
|
with:
|
||||||
|
bot_token: ${{ env.TELEGRAM_BOT_TOKEN }}
|
||||||
|
chat_id: ${{ env.TELEGRAM_CHAT_ID }}
|
||||||
|
message: |
|
||||||
|
❌ **部署失败!**
|
||||||
|
|
||||||
📦 项目: ${{ github.repository }}
|
📦 **项目**: ${{ github.repository }}
|
||||||
🌿 分支: ${{ github.ref_name }}
|
🌿 **分支**: ${{ github.ref_name }}
|
||||||
🔖 版本: ${{ env.VERSION }}
|
🔖 **版本**: ${{ env.VERSION }}
|
||||||
🎯 构建目标: ${{ env.BUILD_TARGET }}
|
🎯 **构建目标**: ${{ env.BUILD_TARGET }}
|
||||||
|
📝 **提交**: ${{ github.sha }}
|
||||||
|
👤 **提交者**: ${{ github.actor }}
|
||||||
|
🕐 **时间**: ${{ github.event.head_commit.timestamp }}
|
||||||
|
|
||||||
🕐 时间: $(date '+%Y-%m-%d %H:%M:%S')
|
⚠️ **请检查构建日志获取详细信息**
|
||||||
|
parse_mode: Markdown
|
||||||
请检查构建日志获取详细信息。"
|
|
||||||
|
|
||||||
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage" \
|
|
||||||
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
|
|
||||||
-d text="$MESSAGE" \
|
|
||||||
-d parse_mode="HTML"
|
|
||||||
|
|||||||
Reference in New Issue
Block a user