fix(ci): 合并构建和部署步骤解决产物共享问题

问题:
- build-artifacts和deploy-production在不同容器运行
- 构建产物无法共享,导致部署步骤被取消

修复:
- 将构建和部署合并为build-and-deploy单一步骤
- 确保构建产物在同一容器内可用于部署
- 简化CI流程,修复步骤依赖关系
This commit is contained in:
张翔
2026-03-29 22:47:43 +08:00
parent 8531efcb5c
commit f1ff06d268
+58 -101
View File
@@ -2,36 +2,35 @@
# Novalon Website - 全自动CI/CD工作流 # Novalon Website - 全自动CI/CD工作流
# ============================================ # ============================================
# 发布策略:feature -> dev -> release -> main # 发布策略:feature -> dev -> release -> main
# #
# 分支角色与流程: # 分支角色与流程:
# 1. feature/** 分支:开发新功能 # 1. feature/** 分支:开发新功能
# - 触发:PR和push # - 触发:PR和push
# - 执行:Lint + TypeCheck + Smoke Test # - 执行:Lint + TypeCheck + Smoke Test
# - 合并到:dev分支 # - 合并到:dev分支
# #
# 2. dev 分支:开发集成 # 2. dev 分支:开发集成
# - 触发:push # - 触发:push
# - 执行:完整测试套件(不部署) # - 执行:完整测试套件(不部署)
# - 创建/合并到:release/**分支 # - 创建/合并到:release/**分支
# #
# 3. release/** 分支:生产环境代码 # 3. release/** 分支:生产环境代码
# - 触发:push # - 触发:push
# - 执行:代码检查 + 构建产物 + 同步部署 # - 执行:代码检查 + 构建部署一体化
# - 部署到:生产环境(139.155.109.62) # - 部署到:生产环境(139.155.109.62)
# - 归档到:main分支 # - 归档到:main分支
# #
# 4. main 分支:稳定代码归档 # 4. main 分支:稳定代码归档
# - 只读分支 # - 只读分支
# - 仅接收来自release的自动归档 # - 仅接收来自release的自动归档
# #
# 流水线阶段: # 流水线阶段:
# 阶段0: 依赖安装(统一缓存) # 阶段0: 依赖安装(统一缓存)
# 阶段1: 并行代码质量检查 (lint, type-check, security-scan) # 阶段1: 并行代码质量检查 (lint, type-check, security-scan)
# 阶段2: 单元测试 -> E2E测试 (允许失败) # 阶段2: 测试 (unit-tests, e2e-tests - 仅dev分支)
# 阶段3: 构建生产产物 (release分支) # 阶段3: 构建并部署到生产环境 (release分支,一体化)
# 阶段4: 同步产物到生产服务器并部署 (release分支) # 阶段4: 归档到main分支 (release分支)
# 阶段5: 归档到main分支 (仅release分支) # 阶段5: 企业微信通知
# 阶段6: 企业微信通知
# ============================================ # ============================================
variables: variables:
@@ -54,11 +53,6 @@ steps:
event: event:
- push - push
- pull_request - pull_request
branch:
- feature/**
- dev
- release
- release/**
# ============================================ # ============================================
# 阶段1: 并行代码质量检查 # 阶段1: 并行代码质量检查
@@ -78,11 +72,6 @@ steps:
event: event:
- push - push
- pull_request - pull_request
branch:
- feature/**
- dev
- release
- release/**
type-check: type-check:
image: *node_image image: *node_image
@@ -99,11 +88,6 @@ steps:
event: event:
- push - push
- pull_request - pull_request
branch:
- feature/**
- dev
- release
- release/**
security-scan: security-scan:
image: *node_image image: *node_image
@@ -121,11 +105,6 @@ steps:
event: event:
- push - push
- pull_request - pull_request
branch:
- feature/**
- dev
- release
- release/**
# ============================================ # ============================================
# 阶段2: 测试 (仅dev分支,允许失败) # 阶段2: 测试 (仅dev分支,允许失败)
@@ -177,21 +156,55 @@ steps:
- dev - dev
# ============================================ # ============================================
# 阶段3: 构建生产产物 (release分支) # 阶段3: 构建并部署到生产环境 (release分支)
# ============================================ # ============================================
build-artifacts: build-and-deploy:
image: *node_image image: *node_image
environment: environment:
NODE_ENV: production NODE_ENV: production
NEXT_TELEMETRY_DISABLED: 1 NEXT_TELEMETRY_DISABLED: 1
SSH_PRIVATE_KEY:
from_secret: ssh_private_key
depends_on: depends_on:
- lint - lint
- type-check - type-check
commands: commands:
- echo "Building production artifacts..." - echo "=== Step 1: 构建生产产物 ==="
- npm run build - npm run build
- echo "✅ Build completed" - echo "✅ 构建完成"
- ls -la dist/ - ls -la dist/
- echo "=== Step 2: 部署到生产环境 ==="
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H 139.155.109.62 >> ~/.ssh/known_hosts
- echo "Pre-deployment checks..."
- ssh root@139.155.109.62 "echo 'Server connection OK'"
- ssh root@139.155.109.62 "df -h | grep -E '/$|/home'"
- echo "Syncing build artifacts to production server..."
- rsync -avz --delete dist/ root@139.155.109.62:/home/novalon/docker-app/novalon-website/dist/
- rsync -avz public/ root@139.155.109.62:/home/novalon/docker-app/novalon-website/public/
- rsync -avz package.json package-lock.json root@139.155.109.62:/home/novalon/docker-app/novalon-website/
- rsync -avz Dockerfile.prod docker-compose.server.yml root@139.155.109.62:/home/novalon/docker-app/novalon-website/
- rsync -avz scripts/deploy-production.sh root@139.155.109.62:/home/novalon/docker-app/novalon-website/scripts/
- rsync -avz .env.production root@139.155.109.62:/home/novalon/docker-app/novalon-website/ 2>/dev/null || echo "No .env.production file"
- |
ssh root@139.155.109.62 << 'EOF'
set -e
cd /home/novalon/docker-app/novalon-website
if [ -f docker-compose.server.yml ]; then
mv docker-compose.server.yml docker-compose.yml
fi
chmod +x scripts/deploy-production.sh
./scripts/deploy-production.sh
EOF
- echo "✅ 生产环境部署完成!"
volumes: volumes:
- /tmp/npm-cache:/root/.npm - /tmp/npm-cache:/root/.npm
- /tmp/node-modules-cache:/woodpecker/src/node_modules - /tmp/node-modules-cache:/woodpecker/src/node_modules
@@ -203,57 +216,7 @@ steps:
- release/** - release/**
# ============================================ # ============================================
# 阶段4: 部署到生产环境 (release分支) # 阶段4: 归档到main分支 (release分支)
# ============================================
deploy-production:
image: alpine/git:latest
environment:
DEPLOY_ENV: production
SSH_PRIVATE_KEY:
from_secret: ssh_private_key
depends_on:
- build-artifacts
commands:
- echo "Deploying to production environment..."
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H 139.155.109.62 >> ~/.ssh/known_hosts
- echo "Pre-deployment checks..."
- ssh root@139.155.109.62 "echo 'Server connection OK'"
- ssh root@139.155.109.62 "df -h | grep -E '/$|/home'"
- echo "Syncing build artifacts to production server..."
- rsync -avz --delete dist/ root@139.155.109.62:/home/novalon/docker-app/novalon-website/dist/
- rsync -avz public/ root@139.155.109.62:/home/novalon/docker-app/novalon-website/public/
- rsync -avz package.json package-lock.json root@139.155.109.62:/home/novalon/docker-app/novalon-website/
- rsync -avz Dockerfile.prod docker-compose.server.yml root@139.155.109.62:/home/novalon/docker-app/novalon-website/
- rsync -avz scripts/deploy-production.sh root@139.155.109.62:/home/novalon/docker-app/novalon-website/scripts/
- rsync -avz .env.production root@139.155.109.62:/home/novalon/docker-app/novalon-website/ 2>/dev/null || echo "No .env.production file"
- |
ssh root@139.155.109.62 << 'EOF'
set -e
cd /home/novalon/docker-app/novalon-website
if [ -f docker-compose.server.yml ]; then
mv docker-compose.server.yml docker-compose.yml
fi
chmod +x scripts/deploy-production.sh
./scripts/deploy-production.sh
EOF
- echo "✅ Production deployment completed!"
when:
event:
- push
branch:
- release
- release/**
# ============================================
# 阶段5: 归档到main分支 (release分支)
# ============================================ # ============================================
archive-to-main: archive-to-main:
image: alpine/git:latest image: alpine/git:latest
@@ -261,7 +224,7 @@ steps:
SSH_PRIVATE_KEY: SSH_PRIVATE_KEY:
from_secret: ssh_private_key from_secret: ssh_private_key
depends_on: depends_on:
- deploy-production - build-and-deploy
commands: commands:
- echo "Archiving to main branch..." - echo "Archiving to main branch..."
- mkdir -p ~/.ssh - mkdir -p ~/.ssh
@@ -272,20 +235,20 @@ steps:
set -e set -e
git config --global user.email "ci@novalon.cn" git config --global user.email "ci@novalon.cn"
git config --global user.name "Woodpecker CI" git config --global user.name "Woodpecker CI"
git remote set-url origin git@git.f.novalon.cn:novalon/novalon-website.git git remote set-url origin git@git.f.novalon.cn:novalon/novalon-website.git
git fetch origin git fetch origin
CURRENT_BRANCH="${CI_COMMIT_BRANCH}" CURRENT_BRANCH="${CI_COMMIT_BRANCH}"
echo "Current branch: $CURRENT_BRANCH" echo "Current branch: $CURRENT_BRANCH"
git checkout main git checkout main
git pull origin main git pull origin main
git merge "$CURRENT_BRANCH" --no-ff -m "chore: 归档${CURRENT_BRANCH} ${CI_COMMIT_SHA:0:7}" git merge "$CURRENT_BRANCH" --no-ff -m "chore: 归档${CURRENT_BRANCH} ${CI_COMMIT_SHA:0:7}"
VERSION_TAG="v$(date +%Y.%m.%d)-${CI_COMMIT_SHA:0:7}" VERSION_TAG="v$(date +%Y.%m.%d)-${CI_COMMIT_SHA:0:7}"
git tag -a "$VERSION_TAG" -m "Release $(date +%Y-%m-%d) from ${CURRENT_BRANCH}" git tag -a "$VERSION_TAG" -m "Release $(date +%Y-%m-%d) from ${CURRENT_BRANCH}"
for i in {1..3}; do for i in {1..3}; do
if git push origin main && git push origin --tags; then if git push origin main && git push origin --tags; then
echo "✅ Archive succeeded! Version: $VERSION_TAG" echo "✅ Archive succeeded! Version: $VERSION_TAG"
@@ -294,7 +257,7 @@ steps:
echo "Retry $i/3..." echo "Retry $i/3..."
sleep 5 sleep 5
done done
echo "⚠️ Archive failed, but deployment succeeded" echo "⚠️ Archive failed, but deployment succeeded"
exit 0 exit 0
when: when:
@@ -303,11 +266,9 @@ steps:
branch: branch:
- release - release
- release/** - release/**
status:
- success
# ============================================ # ============================================
# 阶段6: 企业微信通知 # 阶段5: 企业微信通知
# ============================================ # ============================================
notify-wechat-success: notify-wechat-success:
image: curlimages/curl:latest image: curlimages/curl:latest
@@ -324,8 +285,6 @@ steps:
branch: branch:
- release - release
- release/** - release/**
status:
- success
notify-wechat-failure: notify-wechat-failure:
image: curlimages/curl:latest image: curlimages/curl:latest
@@ -333,7 +292,7 @@ steps:
WECHAT_WEBHOOK: WECHAT_WEBHOOK:
from_secret: wechat_webhook from_secret: wechat_webhook
depends_on: depends_on:
- deploy-production - build-and-deploy
commands: commands:
- sh scripts/notify-wechat.sh failure - sh scripts/notify-wechat.sh failure
when: when:
@@ -342,8 +301,6 @@ steps:
branch: branch:
- release - release
- release/** - release/**
status:
- failure
workspace: workspace:
base: /woodpecker base: /woodpecker