Compare commits
5 Commits
618ac0bf8c
...
cicd
| Author | SHA1 | Date | |
|---|---|---|---|
| bd4091524e | |||
| 5b7f778551 | |||
| 38f64f770d | |||
| 2ee249f6f7 | |||
| e3698a8a60 |
+203
-75
@@ -37,7 +37,36 @@ jobs:
|
||||
|
||||
steps:
|
||||
- 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)
|
||||
run: |
|
||||
@@ -122,7 +151,9 @@ jobs:
|
||||
echo "canvas_binary_host_mirror=https://registry.npmmirror.com/-/binary/canvas" >> .npmrc
|
||||
|
||||
- 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:
|
||||
path: ~/.bun
|
||||
key: bun-${{ runner.os }}-${{ matrix.node }}-${{ hashFiles('bun.lock') }}
|
||||
@@ -131,7 +162,9 @@ jobs:
|
||||
bun-${{ runner.os }}-
|
||||
|
||||
- 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:
|
||||
path: |
|
||||
node_modules
|
||||
@@ -175,11 +208,15 @@ jobs:
|
||||
echo "✅ 缓存目录已准备完成"
|
||||
|
||||
- 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:
|
||||
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: |
|
||||
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-${{ hashFiles('apps/**/package.json') }}-${{ hashFiles('packages/**/package.json') }}-
|
||||
turbo-${{ runner.os }}-${{ hashFiles('turbo.json') }}-
|
||||
turbo-${{ runner.os }}-
|
||||
|
||||
- name: 安装依赖 (bun)
|
||||
@@ -269,7 +306,9 @@ jobs:
|
||||
echo "BRANCH=${{ github.ref_name }}" >> $GITHUB_ENV
|
||||
|
||||
- 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:
|
||||
path: |
|
||||
apps/admin/.next/cache
|
||||
@@ -280,7 +319,9 @@ jobs:
|
||||
nextcache-${{ runner.os }}-
|
||||
|
||||
- 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:
|
||||
path: |
|
||||
apps/admin/.next
|
||||
@@ -293,7 +334,9 @@ jobs:
|
||||
build-${{ runner.os }}-
|
||||
|
||||
- name: Cache ESLint
|
||||
uses: https://gitea.cn/actions/cache@v3
|
||||
if: env.CACHE_AVAILABLE == 'true'
|
||||
uses: actions/cache@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
path: |
|
||||
.eslintcache
|
||||
@@ -304,7 +347,9 @@ jobs:
|
||||
eslint-${{ runner.os }}-
|
||||
|
||||
- name: Cache TypeScript
|
||||
uses: https://gitea.cn/actions/cache@v3
|
||||
if: env.CACHE_AVAILABLE == 'true'
|
||||
uses: actions/cache@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
path: |
|
||||
.tsbuildinfo
|
||||
@@ -359,16 +404,34 @@ jobs:
|
||||
docker push ${{ env.DOCKER_REGISTRY }}/ppanel/ppanel-user-web:${{ env.VERSION }}
|
||||
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: 部署管理面板到服务器
|
||||
if: env.BUILD_TARGET == 'admin' || env.BUILD_TARGET == 'both'
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
host: ${{ env.SSH_HOST }}
|
||||
username: ${{ env.SSH_USER }}
|
||||
password: ${{ env.SSH_PASSWORD }}
|
||||
port: ${{ env.SSH_PORT }}
|
||||
timeout: 300s
|
||||
command_timeout: 600s
|
||||
script: |
|
||||
@@ -435,24 +498,53 @@ jobs:
|
||||
|
||||
# 安全停止和移除容器
|
||||
echo "检查现有容器状态..."
|
||||
if docker ps -q -f name=ppanel-admin-web | grep -q .; then
|
||||
echo "停止运行中的容器..."
|
||||
docker stop ppanel-admin-web --time=10 || true
|
||||
sleep 3
|
||||
fi
|
||||
CONTAINER_NAME="ppanel-admin-web"
|
||||
|
||||
if docker ps -aq -f name=ppanel-admin-web | grep -q .; then
|
||||
echo "移除现有容器..."
|
||||
# 等待容器完全停止
|
||||
for i in {1..10}; do
|
||||
if docker rm ppanel-admin-web 2>/dev/null; then
|
||||
echo "容器移除成功"
|
||||
# 检查容器是否存在
|
||||
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
|
||||
echo "发现现有容器,开始清理..."
|
||||
|
||||
# 检查容器是否正在运行
|
||||
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
|
||||
echo "停止运行中的容器..."
|
||||
docker stop $CONTAINER_NAME --time=15 || true
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
# 检查容器是否正在被移除
|
||||
echo "检查容器移除状态..."
|
||||
for i in {1..15}; do
|
||||
# 尝试获取容器状态
|
||||
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
|
||||
|
||||
if [ "$CONTAINER_STATUS" = "not_found" ]; then
|
||||
echo "✅ 容器已不存在"
|
||||
break
|
||||
elif [ "$CONTAINER_STATUS" = "removing" ]; then
|
||||
echo "⏳ 容器正在移除中,等待完成... $i/15"
|
||||
sleep 3
|
||||
else
|
||||
echo "等待容器停止... $i/10"
|
||||
echo "尝试移除容器... $i/15"
|
||||
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
|
||||
echo "✅ 容器移除成功"
|
||||
break
|
||||
else
|
||||
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
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "✅ 未发现现有容器"
|
||||
fi
|
||||
|
||||
echo "启动新容器..."
|
||||
@@ -484,12 +576,13 @@ jobs:
|
||||
if: env.BUILD_TARGET == 'user' || env.BUILD_TARGET == 'both'
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.HOST }}
|
||||
username: ${{ secrets.USERNAME }}
|
||||
key: ${{ secrets.KEY }}
|
||||
port: ${{ secrets.PORT }}
|
||||
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 "DOCKER_REGISTRY: ${{ env.DOCKER_REGISTRY }}"
|
||||
@@ -554,24 +647,53 @@ jobs:
|
||||
|
||||
# 安全停止和移除容器
|
||||
echo "检查现有容器状态..."
|
||||
if docker ps -q -f name=ppanel-user-web | grep -q .; then
|
||||
echo "停止运行中的容器..."
|
||||
docker stop ppanel-user-web --time=10 || true
|
||||
sleep 3
|
||||
fi
|
||||
CONTAINER_NAME="ppanel-user-web"
|
||||
|
||||
if docker ps -aq -f name=ppanel-user-web | grep -q .; then
|
||||
echo "移除现有容器..."
|
||||
# 等待容器完全停止
|
||||
for i in {1..10}; do
|
||||
if docker rm ppanel-user-web 2>/dev/null; then
|
||||
echo "容器移除成功"
|
||||
# 检查容器是否存在
|
||||
if docker ps -aq -f name=$CONTAINER_NAME | grep -q .; then
|
||||
echo "发现现有容器,开始清理..."
|
||||
|
||||
# 检查容器是否正在运行
|
||||
if docker ps -q -f name=$CONTAINER_NAME | grep -q .; then
|
||||
echo "停止运行中的容器..."
|
||||
docker stop $CONTAINER_NAME --time=15 || true
|
||||
sleep 5
|
||||
fi
|
||||
|
||||
# 检查容器是否正在被移除
|
||||
echo "检查容器移除状态..."
|
||||
for i in {1..15}; do
|
||||
# 尝试获取容器状态
|
||||
CONTAINER_STATUS=$(docker inspect $CONTAINER_NAME --format='{{.State.Status}}' 2>/dev/null || echo "not_found")
|
||||
|
||||
if [ "$CONTAINER_STATUS" = "not_found" ]; then
|
||||
echo "✅ 容器已不存在"
|
||||
break
|
||||
elif [ "$CONTAINER_STATUS" = "removing" ]; then
|
||||
echo "⏳ 容器正在移除中,等待完成... $i/15"
|
||||
sleep 3
|
||||
else
|
||||
echo "等待容器停止... $i/10"
|
||||
echo "尝试移除容器... $i/15"
|
||||
if docker rm -f $CONTAINER_NAME 2>/dev/null; then
|
||||
echo "✅ 容器移除成功"
|
||||
break
|
||||
else
|
||||
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
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "✅ 未发现现有容器"
|
||||
fi
|
||||
|
||||
echo "启动新容器..."
|
||||
@@ -599,39 +721,45 @@ jobs:
|
||||
docker logs ppanel-user-web || true
|
||||
exit 1
|
||||
|
||||
- name: 发送成功通知到Telegram
|
||||
# 步骤5: TG通知 (成功)
|
||||
- name: 📱 发送成功通知到Telegram
|
||||
if: success()
|
||||
run: |
|
||||
MESSAGE="✅ 部署成功!
|
||||
|
||||
📦 项目: ${{ github.repository }}
|
||||
🌿 分支: ${{ github.ref_name }}
|
||||
🔖 版本: ${{ env.VERSION }}
|
||||
🎯 构建目标: ${{ env.BUILD_TARGET }}
|
||||
🔗 API地址: ${{ env.NEXT_PUBLIC_API_URL }}
|
||||
|
||||
🕐 时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
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"
|
||||
uses: chapvic/telegram-notify@master
|
||||
with:
|
||||
bot_token: ${{ env.TELEGRAM_BOT_TOKEN }}
|
||||
chat_id: ${{ env.TELEGRAM_CHAT_ID }}
|
||||
message: |
|
||||
✅ **部署成功!**
|
||||
|
||||
📦 **项目**: ${{ github.repository }}
|
||||
🌿 **分支**: ${{ github.ref_name }}
|
||||
🔖 **版本**: ${{ env.VERSION }}
|
||||
🎯 **构建目标**: ${{ env.BUILD_TARGET }}
|
||||
🔗 **API地址**: ${{ env.NEXT_PUBLIC_API_URL }}
|
||||
📝 **提交**: ${{ github.sha }}
|
||||
👤 **提交者**: ${{ github.actor }}
|
||||
🕐 **时间**: ${{ github.event.head_commit.timestamp }}
|
||||
|
||||
🚀 **服务已成功部署到生产环境**
|
||||
parse_mode: Markdown
|
||||
|
||||
- name: 发送失败通知到Telegram
|
||||
# 步骤5: TG通知 (失败)
|
||||
- name: 📱 发送失败通知到Telegram
|
||||
if: failure()
|
||||
run: |
|
||||
MESSAGE="❌ 部署失败!
|
||||
|
||||
📦 项目: ${{ github.repository }}
|
||||
🌿 分支: ${{ github.ref_name }}
|
||||
🔖 版本: ${{ env.VERSION }}
|
||||
🎯 构建目标: ${{ env.BUILD_TARGET }}
|
||||
|
||||
🕐 时间: $(date '+%Y-%m-%d %H:%M:%S')
|
||||
|
||||
请检查构建日志获取详细信息。"
|
||||
|
||||
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"
|
||||
uses: chapvic/telegram-notify@master
|
||||
with:
|
||||
bot_token: ${{ env.TELEGRAM_BOT_TOKEN }}
|
||||
chat_id: ${{ env.TELEGRAM_CHAT_ID }}
|
||||
message: |
|
||||
❌ **部署失败!**
|
||||
|
||||
📦 **项目**: ${{ github.repository }}
|
||||
🌿 **分支**: ${{ github.ref_name }}
|
||||
🔖 **版本**: ${{ env.VERSION }}
|
||||
🎯 **构建目标**: ${{ env.BUILD_TARGET }}
|
||||
📝 **提交**: ${{ github.sha }}
|
||||
👤 **提交者**: ${{ github.actor }}
|
||||
🕐 **时间**: ${{ github.event.head_commit.timestamp }}
|
||||
|
||||
⚠️ **请检查构建日志获取详细信息**
|
||||
parse_mode: Markdown
|
||||
|
||||
Reference in New Issue
Block a user