|
15456
|
10814
|
6
|
5
|
40dae5944f158653af8288a3f38b6c97e8ce9f06
|
0
|
AI 模块单元测试
|
0
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
ai-unit-test:
name: AI 模块单元测试
runs-on: ubuntu-latest
if: |
needs.detect-changes.outputs.ai-modules == 'true' ||
needs.detect-changes.outputs.backend == 'true' ||
(github.event.inputs.run_ai_tests != 'false')
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: AI Agents 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agents --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Agent Skills 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agent-skills --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Review Queue 模块测试
run: |
cd backend
npx vitest run src/modules/ai-review-queue --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Copilot 模块测试
run: |
cd backend
npx vitest run src/modules/ai-copilot --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: Lead Scoring AI 模块测试
run: |
cd backend
npx vitest run src/modules/lead-scoring-ai --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI 状态机测试
run: |
cd backend
npx vitest run \
src/shared/state-machines/__tests__/ai-agent.machine.test.ts \
src/shared/state-machines/__tests__/ai-task.machine.test.ts \
src/shared/state-machines/__tests__/training-plan.machine.test.ts \
--reporter=verbose --passWithNoTests
- if: always()
name: 生成 AI 测试摘要
run: |
echo "## AI 模块测试结果" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| AI 模块 | 测试文件数 |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-----------|" >> $GITHUB_STEP_SUMMARY
echo "| ai-agents | 4 (service/controller/schema/permissions) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-agent-skills | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-review-queue | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-copilot | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| lead-scoring-ai | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| AI 状态机 | 3 (ai-agent/ai-task/training-plan) |" >> $GITHUB_STEP_SUMMARY
...
|
ai-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1775180539
|
1775180412
|
1775180539
|
|
0
|
|
0
|
Edit
Delete
|
|
15496
|
10817
|
6
|
5
|
9d69e1960ec649a49c0c6f307c0fc197f47ee4c4
|
0
|
AI 模块单元测试
|
1
|
name: Test Pipeline
"on":
push:
name: Test Pipeline
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
coverage_threshold:
description: '覆盖率阈值 (%)'
required: false
default: '80'
run_ai_tests:
description: '运行 AI 模块测试'
required: false
default: 'true'
type: boolean
run_api_tests:
description: '运行 API 集成测试'
required: false
default: 'true'
type: boolean
run_security_audit:
description: '运行安全审计'
required: false
default: 'true'
type: boolean
env:
COVERAGE_THRESHOLD: ${{ github.event.inputs.coverage_threshold || '80' }}
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
ai-unit-test:
name: AI 模块单元测试
runs-on: ubuntu-latest
if: |
needs.detect-changes.outputs.ai-modules == 'true' ||
needs.detect-changes.outputs.backend == 'true' ||
(github.event.inputs.run_ai_tests != 'false')
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: 恢复依赖缓存
uses: actions/cache/restore@v4
with:
key: pipeline-deps-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
path: |
node_modules
backend/node_modules
frontend/node_modules
shared/node_modules
shared/dist
e2e/node_modules
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: AI Agents 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agents --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Agent Skills 模块测试
run: |
cd backend
npx vitest run src/modules/ai-agent-skills --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Review Queue 模块测试
run: |
cd backend
npx vitest run src/modules/ai-review-queue --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI Copilot 模块测试
run: |
cd backend
npx vitest run src/modules/ai-copilot --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: Lead Scoring AI 模块测试
run: |
cd backend
npx vitest run src/modules/lead-scoring-ai --reporter=verbose --passWithNoTests
env:
NODE_ENV: test
JWT_SECRET: test-jwt-secret
- name: AI 状态机测试
run: |
cd backend
npx vitest run \
src/shared/state-machines/__tests__/ai-agent.machine.test.ts \
src/shared/state-machines/__tests__/ai-task.machine.test.ts \
src/shared/state-machines/__tests__/training-plan.machine.test.ts \
--reporter=verbose --passWithNoTests
- if: always()
name: 生成 AI 测试摘要
run: |
echo "## AI 模块测试结果" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| AI 模块 | 测试文件数 |" >> $GITHUB_STEP_SUMMARY
echo "|---------|-----------|" >> $GITHUB_STEP_SUMMARY
echo "| ai-agents | 4 (service/controller/schema/permissions) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-agent-skills | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-review-queue | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| ai-copilot | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| lead-scoring-ai | 1 (service) |" >> $GITHUB_STEP_SUMMARY
echo "| AI 状态机 | 3 (ai-agent/ai-task/training-plan) |" >> $GITHUB_STEP_SUMMARY
...
|
ai-unit-test
|
["backend-lint"]
|
["ubuntu-latest"]
|
12847
|
4
|
1775186049
|
1775186049
|
1775180541
|
1775186049
|
|
1
|
|
0
|
Edit
Delete
|
|
2123
|
1380
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
...
|
analyze
|
null
|
["ubuntu-latest"]
|
1358
|
2
|
1772248309
|
1772249370
|
1772248015
|
1772249370
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
2605
|
1860
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
...
|
analyze
|
null
|
["ubuntu-latest"]
|
1836
|
2
|
1772391612
|
1772391703
|
1772391612
|
1772391704
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
4744
|
3887
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
...
|
analyze
|
null
|
["ubuntu-latest"]
|
3882
|
2
|
1772996434
|
1772996471
|
1772996432
|
1772996471
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
6829
|
5908
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
...
|
analyze
|
null
|
["ubuntu-latest"]
|
5915
|
2
|
1773601235
|
1773601637
|
1773601232
|
1773601638
|
NULL
|
NULL
|
|
0
|
Edit
Delete
|
|
8729
|
7229
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
7538
|
2
|
1774206041
|
1774206127
|
1774206040
|
1774206127
|
|
0
|
|
0
|
Edit
Delete
|
|
9089
|
7322
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
7856
|
2
|
1774234842
|
1774234854
|
1774234840
|
1774234854
|
|
0
|
|
0
|
Edit
Delete
|
|
12953
|
9535
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
10950
|
2
|
1774839621
|
1774839661
|
1774839618
|
1774839661
|
|
0
|
|
0
|
Edit
Delete
|
|
16476
|
11711
|
13
|
5
|
6c80c00976d1c5ac4aaa5f76d10cf1e7b4f59448
|
0
|
Analyze (java)
|
1
|
name: CodeQL Analysis
"on":
push:
name: CodeQL Analysis
"on":
push:
branches: [develop, master, main]
pull_request:
branches: [develop, master, main]
schedule:
# 每周一凌晨3点运行
- cron: '0 3 * * 1'
jobs:
analyze:
name: Analyze (java)
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Java
uses: actions/setup-java@v4
with:
cache: gradle
distribution: temurin
java-version: "17"
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: +security-extended,security-and-quality
- name: Grant Execute Permission
run: chmod +x ./gradlew
- name: Build
run: ./gradlew assembleDebug --stacktrace
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: /language:${{ matrix.language }}
timeout-minutes: "30"
strategy:
fail-fast: "false"
matrix:
language:
- java
permissions:
actions: read
contents: read
security-events: write
...
|
analyze
|
null
|
["ubuntu-latest"]
|
13769
|
2
|
1775444420
|
1775444445
|
1775444418
|
1775444445
|
|
0
|
|
0
|
Edit
Delete
|
|
7854
|
6705
|
6
|
5
|
e112d45af414e4862c0328abad7c4df74d3c1dbf
|
0
|
API 端到端测试
|
0
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1773832745
|
1773831750
|
1773832745
|
|
0
|
|
0
|
Edit
Delete
|
|
7916
|
6715
|
6
|
5
|
b7eb415d7a9689f1efec941bcb2dcd7d098e9c28
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
6838
|
4
|
1773833391
|
1773833391
|
1773832746
|
1773833391
|
|
1
|
|
0
|
Edit
Delete
|
|
8279
|
6998
|
6
|
5
|
bd59e5501292cb061719f669c7a7b7afd4f1a0b7
|
0
|
API 端到端测试
|
0
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1773913346
|
1773912914
|
1773913346
|
|
0
|
|
0
|
Edit
Delete
|
|
8337
|
7006
|
6
|
5
|
01a8ea9191c28b210d2abb3db3cbc65db42fc801
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7204
|
4
|
1773914274
|
1773914275
|
1773913347
|
1773914275
|
|
1
|
|
0
|
Edit
Delete
|
|
8472
|
7071
|
6
|
5
|
9771b23ae7aaee164f15f9c4ccbdb18eb68fc71f
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7319
|
4
|
1773930001
|
1773930001
|
1773929409
|
1773930002
|
|
1
|
|
0
|
Edit
Delete
|
|
8581
|
7116
|
6
|
5
|
979d9c81063fbda12f1445bf80b0c0027b0fbac2
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7422
|
4
|
1773940818
|
1773940818
|
1773939781
|
1773940819
|
|
1
|
|
0
|
Edit
Delete
|
|
8770
|
7234
|
6
|
5
|
0900b15d607e5c78f97fec16a73357ad4f814390
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7601
|
4
|
1774222044
|
1774222044
|
1774220986
|
1774222044
|
|
1
|
|
0
|
Edit
Delete
|
|
8846
|
7251
|
6
|
5
|
80c2bdb2f93a19aa53d16ded06387b70c6084bf8
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7664
|
4
|
1774223481
|
1774223481
|
1774223021
|
1774223482
|
|
1
|
|
0
|
Edit
Delete
|
|
8917
|
7263
|
6
|
5
|
df7b6f46170cb46db4771dd1e07991b0b13d90a0
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7724
|
4
|
1774223975
|
1774223975
|
1774223518
|
1774223975
|
|
1
|
|
0
|
Edit
Delete
|
|
9021
|
7293
|
6
|
5
|
339ea969ec2633756fb1a155d47723d0f61396a4
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
7817
|
4
|
1774229656
|
1774229656
|
1774229064
|
1774229656
|
|
1
|
|
0
|
Edit
Delete
|
|
9228
|
7419
|
6
|
5
|
67078f9a95f53530156ad27027eafe15a3126e89
|
0
|
API 端到端测试
|
1
|
name: Integration Tests
"on":
push:
name: Integration Tests
"on":
push:
branches: [main, develop, 'feature/**', 'claude/**']
pull_request:
branches: [main, develop]
workflow_dispatch:
inputs:
run_all_tests:
description: '运行所有集成测试(包括慢速测试)'
required: false
default: 'false'
type: boolean
env:
NODE_VERSION: "20"
PNPM_VERSION: "8"
jobs:
api-e2e-tests:
name: API 端到端测试
runs-on: ubuntu-latest
if: needs.detect-changes.outputs.backend == 'true'
steps:
- uses: actions/checkout@v4
- name: 安装 pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- name: 设置 Node.js
uses: actions/setup-node@v4
with:
cache: pnpm
node-version: ${{ env.NODE_VERSION }}
- name: 安装依赖
run: pnpm install --frozen-lockfile
- name: 构建共享包
run: pnpm --filter @juhi/shared run build
- name: 启动测试服务
run: |
docker-compose -f docker-compose.test.yml up -d
sleep 30
- name: 生成 Prisma Client
run: pnpm --filter juhi-api run db:generate
- name: 执行数据库迁移
run: |
cd backend
npx prisma migrate deploy
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
- name: 运行 API 测试
run: pnpm --filter juhi-api run test:api
env:
DATABASE_URL: postgresql://juhi_test:test_password@localhost:5433/juhi_test
REDIS_URL: redis://localhost:6380
KAFKA_BROKERS: localhost:9095
JWT_SECRET: test-jwt-secret
JWT_REFRESH_SECRET: test-jwt-refresh-secret
NODE_ENV: test
- if: always()
name: 停止测试服务
run: docker-compose -f docker-compose.test.yml down -v
- if: always()
name: 上传测试结果
uses: actions/upload-artifact@v4
with:
name: api-e2e-test-results
path: backend/test-results/
retention-days: "7"
...
|
api-e2e-tests
|
["integration-tests"]
|
["ubuntu-latest"]
|
8016
|
4
|
1774263718
|
1774263718
|
1774262378
|
1774263718
|
|
1
|
|
0
|
Edit
Delete
|
|
7841
|
6703
|
6
|
5
|
e112d45af414e4862c0328abad7c4df74d3c1dbf
|
0
|
自动回滚
|
0
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1773832744
|
1773831749
|
1773832744
|
|
0
|
|
0
|
Edit
Delete
|
|
7903
|
6713
|
6
|
5
|
b7eb415d7a9689f1efec941bcb2dcd7d098e9c28
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
6843
|
4
|
1773833402
|
1773833402
|
1773832744
|
1773833402
|
|
1
|
|
0
|
Edit
Delete
|
|
8266
|
6996
|
6
|
5
|
bd59e5501292cb061719f669c7a7b7afd4f1a0b7
|
0
|
自动回滚
|
0
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1773913345
|
1773912912
|
1773913345
|
|
0
|
|
0
|
Edit
Delete
|
|
8324
|
7004
|
6
|
5
|
01a8ea9191c28b210d2abb3db3cbc65db42fc801
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7208
|
4
|
1773914284
|
1773914284
|
1773913345
|
1773914284
|
|
1
|
|
0
|
Edit
Delete
|
|
8459
|
7069
|
6
|
5
|
9771b23ae7aaee164f15f9c4ccbdb18eb68fc71f
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7323
|
4
|
1773930010
|
1773930011
|
1773929408
|
1773930011
|
|
1
|
|
0
|
Edit
Delete
|
|
8568
|
7114
|
6
|
5
|
979d9c81063fbda12f1445bf80b0c0027b0fbac2
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7424
|
4
|
1773940824
|
1773940824
|
1773939780
|
1773940824
|
|
1
|
|
0
|
Edit
Delete
|
|
8757
|
7232
|
6
|
5
|
0900b15d607e5c78f97fec16a73357ad4f814390
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7604
|
4
|
1774222052
|
1774222052
|
1774220985
|
1774222052
|
|
1
|
|
0
|
Edit
Delete
|
|
8833
|
7249
|
6
|
5
|
80c2bdb2f93a19aa53d16ded06387b70c6084bf8
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7668
|
4
|
1774223490
|
1774223490
|
1774223019
|
1774223491
|
|
1
|
|
0
|
Edit
Delete
|
|
8904
|
7261
|
6
|
5
|
df7b6f46170cb46db4771dd1e07991b0b13d90a0
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7728
|
4
|
1774223984
|
1774223984
|
1774223517
|
1774223984
|
|
1
|
|
0
|
Edit
Delete
|
|
9008
|
7291
|
6
|
5
|
339ea969ec2633756fb1a155d47723d0f61396a4
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
7821
|
4
|
1774229665
|
1774229665
|
1774229062
|
1774229665
|
|
1
|
|
0
|
Edit
Delete
|
|
9215
|
7417
|
6
|
5
|
67078f9a95f53530156ad27027eafe15a3126e89
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
8018
|
4
|
1774263723
|
1774263723
|
1774262376
|
1774263723
|
|
1
|
|
0
|
Edit
Delete
|
|
15519
|
10823
|
6
|
5
|
bd59e5501292cb061719f669c7a7b7afd4f1a0b7
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
12865
|
4
|
1775186343
|
1775186343
|
1775181686
|
1775186344
|
|
1
|
|
0
|
Edit
Delete
|
|
15525
|
10824
|
6
|
5
|
84c900df1e544e4eb7070be9278918676c4aec69
|
0
|
自动回滚
|
1
|
name: Deploy
"on":
push:
branc name: Deploy
"on":
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- rollback
skip_tests:
description: '跳过测试(紧急修复时使用)'
required: false
default: false
type: boolean
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback:
name: 自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-production.result == 'failure'
steps:
- name: 配置 SSH
uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.PRODUCTION_SSH_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.PRODUCTION_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行自动回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "=========================================="
echo "检测到部署失败,执行自动回滚..."
echo "=========================================="
# 使用项目回滚脚本
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --confirm -y
else
# 备用回滚逻辑:读取最近一条部署历史
PREV_LINE=$(tail -1 .deploy-history 2>/dev/null)
PREV_API_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f2)
PREV_FRONTEND_IMAGE=$(echo "$PREV_LINE" | cut -d'|' -f3)
if [ -n "$PREV_API_IMAGE" ] && [ "$PREV_API_IMAGE" != "none" ]; then
echo "回滚到: API=$PREV_API_IMAGE, Frontend=$PREV_FRONTEND_IMAGE"
export API_IMAGE="$PREV_API_IMAGE"
export FRONTEND_IMAGE="$PREV_FRONTEND_IMAGE"
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
# 健康检查(带重试)
RETRY=0
MAX_RETRY=12
until curl -sf http://localhost:3000/health > /dev/null 2>&1; do
RETRY=$((RETRY + 1))
if [ $RETRY -ge $MAX_RETRY ]; then
echo "回滚后健康检查失败(60s),请手动介入"
docker compose -f docker-compose.prod.yml logs --tail=30 api
exit 1
fi
sleep 5
done
echo "回滚成功!"
else
echo "无法获取上一版本信息,需要手动回滚"
echo "部署历史:"
cat .deploy-history 2>/dev/null || echo "(空)"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.PRODUCTION_HOST }}
USER: ${{ secrets.PRODUCTION_USER }}
- if: always()
name: 发送回滚通知
uses: 8398a7/action-slack@v3
with:
custom_payload: |
{
"attachments": [{
"color": "${{ job.status == 'success' && 'warning' || 'danger' }}",
"title": "生产环境自动回滚",
"text": "部署失败触发自动回滚\n回滚状态: ${{ job.status }}",
"fields": [
{ "title": "环境", "value": "Production", "short": true },
{ "title": "触发者", "value": "${{ github.actor }}", "short": true },
{ "title": "版本", "value": "${{ needs.build-and-push.outputs.version }}", "short": true }
]
}]
}
status: custom
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
timeout-minutes: "10"
...
|
auto-rollback
|
["deploy-production"]
|
["ubuntu-latest"]
|
12866
|
4
|
1775186345
|
1775186345
|
1775181686
|
1775186346
|
|
1
|
|
0
|
Edit
Delete
|
|
9384
|
7509
|
6
|
5
|
ff3149170c6b0deb6d8151cb962592199b95bdd8
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774286322
|
1774286259
|
1774286322
|
|
0
|
|
0
|
Edit
Delete
|
|
9398
|
7511
|
6
|
5
|
ff3149170c6b0deb6d8151cb962592199b95bdd8
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774286327
|
1774286322
|
1774286327
|
|
0
|
|
0
|
Edit
Delete
|
|
9408
|
7512
|
6
|
5
|
ff3149170c6b0deb6d8151cb962592199b95bdd8
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
8136
|
4
|
1774286342
|
1774286342
|
1774286327
|
1774286342
|
|
1
|
|
0
|
Edit
Delete
|
|
9547
|
7604
|
6
|
5
|
2ec5b7d8079ffd911c7b27a395d5aba3ceafe372
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774312505
|
1774312441
|
1774312505
|
|
0
|
|
0
|
Edit
Delete
|
|
9561
|
7606
|
6
|
5
|
2ec5b7d8079ffd911c7b27a395d5aba3ceafe372
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774312509
|
1774312506
|
1774312509
|
|
0
|
|
0
|
Edit
Delete
|
|
9571
|
7607
|
6
|
5
|
2ec5b7d8079ffd911c7b27a395d5aba3ceafe372
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
8272
|
4
|
1774312523
|
1774312523
|
1774312509
|
1774312524
|
|
1
|
|
0
|
Edit
Delete
|
|
9623
|
7619
|
6
|
5
|
07680473f95a02e139e159147a93ef74e61f3db2
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774314829
|
1774314769
|
1774314829
|
|
0
|
|
0
|
Edit
Delete
|
|
9637
|
7621
|
6
|
5
|
07680473f95a02e139e159147a93ef74e61f3db2
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774314836
|
1774314830
|
1774314836
|
|
0
|
|
0
|
Edit
Delete
|
|
9647
|
7622
|
6
|
5
|
07680473f95a02e139e159147a93ef74e61f3db2
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
8320
|
4
|
1774314851
|
1774314851
|
1774314837
|
1774314852
|
|
1
|
|
0
|
Edit
Delete
|
|
9694
|
7629
|
6
|
5
|
cfe1efeda7265f05374d3bd0036cf684a15f3cb9
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774315759
|
1774315758
|
1774315759
|
|
0
|
|
0
|
Edit
Delete
|
|
9704
|
7630
|
6
|
5
|
cfe1efeda7265f05374d3bd0036cf684a15f3cb9
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774315823
|
1774315760
|
1774315823
|
|
0
|
|
0
|
Edit
Delete
|
|
9718
|
7632
|
6
|
5
|
cfe1efeda7265f05374d3bd0036cf684a15f3cb9
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774315827
|
1774315824
|
1774315827
|
|
0
|
|
0
|
Edit
Delete
|
|
9728
|
7633
|
6
|
5
|
cfe1efeda7265f05374d3bd0036cf684a15f3cb9
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
8363
|
4
|
1774315841
|
1774315841
|
1774315827
|
1774315842
|
|
1
|
|
0
|
Edit
Delete
|
|
9775
|
7640
|
6
|
5
|
8c39619c9cdb0d888d10942bf50533c8238021df
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774317028
|
1774316965
|
1774317028
|
|
0
|
|
0
|
Edit
Delete
|
|
9789
|
7642
|
6
|
5
|
8c39619c9cdb0d888d10942bf50533c8238021df
|
0
|
阿里云自动回滚
|
0
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
0
|
3
|
0
|
1774317033
|
1774317028
|
1774317033
|
|
0
|
|
0
|
Edit
Delete
|
|
9799
|
7643
|
6
|
5
|
8c39619c9cdb0d888d10942bf50533c8238021df
|
0
|
阿里云自动回滚
|
1
|
name: CI/CD Deploy
"on":
# test-pipeli name: CI/CD Deploy
"on":
# test-pipeline 通过后自动触发(仅 main 分支)
workflow_run:
workflows: ["Test Pipeline"]
types: [completed]
branches: [main]
# 版本标签触发完整部署
push:
tags: ['v*']
# 手动触发
workflow_dispatch:
inputs:
environment:
description: '部署环境'
required: true
default: 'staging'
type: choice
options:
- staging
- production
- aliyun
- rollback-production
- rollback-aliyun
skip_tests:
description: '跳过测试(紧急修复)'
required: false
default: false
type: boolean
version:
description: '部署版本号(留空使用自动版本)'
required: false
type: string
env:
IMAGE_PREFIX: ${{ github.repository_owner }}/juhi
NODE_VERSION: "20"
PNPM_VERSION: "8"
REGISTRY: ghcr.io
jobs:
auto-rollback-aliyun:
name: 阿里云自动回滚
runs-on: ubuntu-latest
if: failure() && needs.deploy-aliyun.result == 'failure'
steps:
- uses: webfactory/ssh-agent@v0.8.0
with:
ssh-private-key: ${{ secrets.ALIYUN_SSH_PRIVATE_KEY }}
- name: 配置 SSH Known Hosts
run: |
mkdir -p ~/.ssh
echo "${{ secrets.ALIYUN_SSH_KNOWN_HOSTS }}" >> ~/.ssh/known_hosts
chmod 644 ~/.ssh/known_hosts
- name: 执行回滚
run: |
ssh $USER@$HOST << 'EOF'
cd /opt/juhi
echo "==> 阿里云自动回滚..."
if [ -f "./scripts/rollback.sh" ]; then
chmod +x ./scripts/rollback.sh
./scripts/rollback.sh --version 1 --confirm
else
PREV_VERSION=$(tail -1 .deploy-history 2>/dev/null | cut -d'|' -f3)
if [ -n "$PREV_VERSION" ]; then
docker compose -f docker-compose.prod.yml up -d --no-deps api frontend
echo "==> 回滚完成"
else
echo "无法获取上一版本"
exit 1
fi
fi
EOF
env:
HOST: ${{ secrets.ALIYUN_HOST }}
USER: ${{ secrets.ALIYUN_USER }}
timeout-minutes: "10"
...
|
auto-rollback-aliyun
|
["deploy-aliyun"]
|
["ubuntu-latest"]
|
8409
|
4
|
1774317050
|
1774317050
|
1774317033
|
1774317050
|
|
1
|
|
0
|
Edit
Delete
|