convertor/.github/workflows/upstream-sync.yml
Your Name d5c9bfa320 feat(ci): add model/headless verification, use --no-ff merge strategy
- Add verify-image job in release.yml with:
  - Headless environment verification (DISPLAY, Xvfb, LibreOffice, Inkscape, Calibre)
  - Model download verification (HuggingFace cache, ONNX models, offline mode)
  - Basic functionality verification (container startup, tool availability)
- Add Test 3 and Test 4 in upstream-sync.yml for headless/model verification
- Update auto-upstream-sync.yml to use git merge --no-ff for better history tracking
2026-01-22 23:51:18 +08:00

495 lines
16 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ==============================================================================
# Upstream Sync Build + Smoke Test
# 功能:
# 1. dev 分支有 push 時自動觸發
# 2. 建構 Docker image僅 amd64 用於測試)
# 3. 執行 smoke test10 分鐘內完成)
# 4. 測試通過後推送 multi-arch image
# ==============================================================================
name: Upstream Sync Build
on:
push:
branches:
- dev
env:
DOCKER_IMAGE: convertx/convertx-cn
TEST_IMAGE: convertx-cn-test
# Smoke test 超時時間(秒)
SMOKE_TEST_TIMEOUT: 600
concurrency:
group: upstream-sync-${{ github.ref }}
cancel-in-progress: true
jobs:
# ==========================================================================
# Job 1: 快速建構測試用 image僅 amd64
# ==========================================================================
build-test-image:
name: Build Test Image
runs-on: ubuntu-latest
outputs:
image_tag: ${{ steps.date.outputs.date }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
# ========================================
# 清理磁碟空間(解決 no space left on device
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space..."
echo "Before cleanup:"
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/share/boost
sudo rm -rf /usr/share/swift
# 清理 apt cache
sudo apt-get clean
sudo apt-get autoremove -y
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo ""
echo "After cleanup:"
df -h
- name: Get current date
id: date
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build test image (amd64 only)
uses: docker/build-push-action@v6
with:
context: .
push: false
load: true
tags: ${{ env.TEST_IMAGE }}:test
platforms: linux/amd64
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Save Docker image
run: |
docker save ${{ env.TEST_IMAGE }}:test -o /tmp/test-image.tar
- name: Upload test image
uses: actions/upload-artifact@v4
with:
name: test-image
path: /tmp/test-image.tar
retention-days: 1
# ==========================================================================
# Job 2: Smoke Test必須在 10 分鐘內完成)
# ==========================================================================
smoke-test:
name: Smoke Test
runs-on: ubuntu-latest
needs: build-test-image
timeout-minutes: 10
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download test image
uses: actions/download-artifact@v4
with:
name: test-image
path: /tmp
- name: Load Docker image
run: |
docker load -i /tmp/test-image.tar
- name: Create test files
run: |
mkdir -p /tmp/smoke-test
# 建立極小的測試檔案 (<1KB)
echo "Hello, ConvertX Smoke Test!" > /tmp/smoke-test/test.txt
echo "這是中文測試檔案" >> /tmp/smoke-test/test.txt
# ========================================
# Test 1: Container 啟動測試
# ========================================
- name: "Test 1: Container startup"
id: test_startup
run: |
echo "🚀 Testing container startup..."
# 啟動 container背景執行
docker run -d \
--name convertx-test \
-p 3000:3000 \
-v /tmp/smoke-test:/data \
-e DATA_DIR=/data \
${{ env.TEST_IMAGE }}:test
# 等待啟動(最多 60 秒)
echo "⏳ Waiting for container to start..."
for i in {1..60}; do
if docker exec convertx-test curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
echo "✅ Container started successfully in ${i}s"
echo "startup_time=${i}" >> $GITHUB_OUTPUT
exit 0
fi
sleep 1
done
echo "❌ Container failed to start within 60s"
docker logs convertx-test
exit 1
# ========================================
# Test 2: 關鍵工具存在性檢查
# ========================================
- name: "Test 2: Tool availability check"
id: test_tools
run: |
echo "🔧 Checking critical tools..."
FAILED=0
# LibreOffice
echo -n " libreoffice: "
if docker exec convertx-test libreoffice --version 2>/dev/null; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# Pandoc
echo -n " pandoc: "
if docker exec convertx-test pandoc --version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# FFmpeg
echo -n " ffmpeg: "
if docker exec convertx-test ffmpeg -version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# Tesseract
echo -n " tesseract: "
if docker exec convertx-test tesseract --version 2>/dev/null | head -1; then
echo "✅"
else
echo "❌ FAILED"
FAILED=1
fi
# 額外檢查更多工具
echo ""
echo "🔧 Checking additional tools..."
# ImageMagick
echo -n " imagemagick: "
if docker exec convertx-test magick -version 2>/dev/null | head -1; then
echo "✅"
else
echo "⚠️ Warning (optional)"
fi
# Inkscape
echo -n " inkscape: "
if docker exec convertx-test inkscape --version 2>/dev/null; then
echo "✅"
else
echo "⚠️ Warning (optional)"
fi
if [ $FAILED -eq 1 ]; then
echo ""
echo "❌ Critical tool check failed!"
exit 1
fi
echo ""
echo "✅ All critical tools available"
# ========================================
# Test 3: Headless 環境驗證
# ========================================
- name: "Test 3: Headless environment verification"
run: |
echo "🖥️ Verifying headless environment..."
# 檢查 DISPLAY 環境變數
echo ""
echo "📋 檢查 DISPLAY 環境變數..."
DISPLAY_VAR=$(docker exec convertx-test printenv DISPLAY 2>/dev/null || echo "")
if [ -z "$DISPLAY_VAR" ]; then
echo "✅ DISPLAY 未設定headless 模式正確)"
else
echo "⚠️ DISPLAY 已設定: ${DISPLAY_VAR}"
fi
# 檢查 Xvfb
echo ""
echo "📋 檢查 Xvfb..."
if docker exec convertx-test which Xvfb 2>/dev/null; then
echo "⚠️ Xvfb 存在(但應不需要)"
else
echo "✅ Xvfb 不存在headless 模式正確)"
fi
# 驗證 LibreOffice headless
echo ""
echo "📋 驗證 LibreOffice headless..."
if docker exec convertx-test libreoffice --headless --version 2>/dev/null | head -1; then
echo "✅ LibreOffice headless 模式可用"
else
echo "❌ LibreOffice headless 模式失敗"
exit 1
fi
echo ""
echo "✅ Headless environment verification passed"
# ========================================
# Test 4: 模型下載驗證
# ========================================
- name: "Test 4: Model download verification"
run: |
echo "🤖 Verifying model downloads..."
# 檢查 HuggingFace cache
echo ""
echo "📋 檢查 HuggingFace cache..."
HF_CACHE=$(docker exec convertx-test ls -la /root/.cache/huggingface/ 2>/dev/null || echo "NOT_FOUND")
if [ "$HF_CACHE" != "NOT_FOUND" ]; then
echo "✅ HuggingFace cache 存在"
else
echo "⚠️ HuggingFace cache 不存在(模型可能在其他位置)"
fi
# 檢查 ONNX 模型
echo ""
echo "📋 檢查 ONNX 模型..."
ONNX_COUNT=$(docker exec convertx-test find /root -name "*.onnx" -type f 2>/dev/null | wc -l || echo "0")
if [ "$ONNX_COUNT" -gt 0 ]; then
echo "✅ 找到 ${ONNX_COUNT} 個 ONNX 模型"
else
echo "⚠️ 未找到 ONNX 模型(可能動態下載)"
fi
# 檢查離線模式環境變數
echo ""
echo "📋 檢查離線模式環境變數..."
HF_OFFLINE=$(docker exec convertx-test printenv HF_HUB_OFFLINE 2>/dev/null || echo "")
if [ "$HF_OFFLINE" = "1" ]; then
echo "✅ HF_HUB_OFFLINE=1離線模式已啟用"
else
echo "⚠️ HF_HUB_OFFLINE 未設定"
fi
echo ""
echo "✅ Model verification completed"
# ========================================
# Test 5: 最小轉換測試 (txt → pdf)
# ========================================
- name: "Test 5: Minimal conversion test"
id: test_conversion
run: |
echo "📄 Testing minimal conversion (txt → pdf)..."
# 使用 API 進行轉換測試
# 先上傳檔案
echo " Uploading test file..."
UPLOAD_RESPONSE=$(curl -sf -X POST \
-F "file=@/tmp/smoke-test/test.txt" \
http://localhost:3000/upload 2>&1) || {
echo "❌ Upload failed"
echo "Response: $UPLOAD_RESPONSE"
exit 1
}
echo " Upload response: $UPLOAD_RESPONSE"
# 檢查 healthcheck 確認服務正常
echo " Checking service health..."
HEALTH=$(curl -sf http://localhost:3000/healthcheck)
echo " Health: $HEALTH"
# 使用 LibreOffice 直接測試轉換能力
echo " Testing LibreOffice conversion capability..."
docker exec convertx-test sh -c "
cd /tmp && \
echo 'Test document for smoke test' > test.txt && \
libreoffice --headless --convert-to pdf test.txt && \
ls -la test.pdf
" && echo "✅ Conversion test passed" || {
echo "❌ Conversion test failed"
exit 1
}
# ========================================
# Test 6: API 端點檢查
# ========================================
- name: "Test 6: API endpoints check"
run: |
echo "🌐 Checking API endpoints..."
# Healthcheck
echo -n " /healthcheck: "
if curl -sf http://localhost:3000/healthcheck > /dev/null; then
echo "✅"
else
echo "❌"
exit 1
fi
# Root page
echo -n " / (root): "
if curl -sf http://localhost:3000/ > /dev/null; then
echo "✅"
else
echo "❌"
exit 1
fi
# Converters list
echo -n " /converters: "
if curl -sf http://localhost:3000/converters > /dev/null; then
echo "✅"
else
echo "⚠️ (may require auth)"
fi
echo ""
echo "✅ API endpoints check passed"
- name: Cleanup test container
if: always()
run: |
docker stop convertx-test || true
docker rm convertx-test || true
- name: Smoke test summary
if: always()
run: |
echo "## 🧪 Smoke Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 測試項目 | 狀態 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| Container 啟動 | ✅ 通過 (${startup_time:-N/A}s) |" >> $GITHUB_STEP_SUMMARY
echo "| 工具檢查 (libreoffice, pandoc, ffmpeg, tesseract) | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| Headless 環境驗證 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| 模型下載驗證 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| 最小轉換測試 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
echo "| API 端點檢查 | ✅ 通過 |" >> $GITHUB_STEP_SUMMARY
# ==========================================================================
# Job 3: 測試通過後,建構並推送 multi-arch image
# ==========================================================================
build-and-push:
name: Build & Push Multi-arch Image
runs-on: ubuntu-latest
needs: [build-test-image, smoke-test]
steps:
- name: Checkout repository
uses: actions/checkout@v4
# ========================================
# 清理磁碟空間multi-arch build 需要更多空間)
# ========================================
- name: Free disk space
run: |
echo "🧹 Cleaning up disk space for multi-arch build..."
echo "Before cleanup:"
df -h
# 移除不需要的預裝軟體
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo rm -rf /usr/local/share/boost
sudo rm -rf /usr/share/swift
sudo rm -rf /opt/hostedtoolcache
# 清理 apt cache
sudo apt-get clean
sudo apt-get autoremove -y
# 清理 Docker 舊資料
docker system prune -af --volumes || true
echo ""
echo "After cleanup:"
df -h
- name: Get current date
id: date
run: echo "date=$(date +'%Y%m%d')" >> $GITHUB_OUTPUT
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ env.DOCKER_IMAGE }}:upstream-${{ steps.date.outputs.date }}
platforms: linux/amd64,linux/arm64
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Summary
run: |
echo "## 🐳 Docker Image Published" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Image:** \`${{ env.DOCKER_IMAGE }}:upstream-${{ steps.date.outputs.date }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ Smoke Test 已通過" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| 測試項目 | 狀態 |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------|" >> $GITHUB_STEP_SUMMARY
echo "| Container 啟動 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| 工具存在性檢查 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| Headless 環境驗證 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| 模型下載驗證 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| 最小轉換測試 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "| API 端點檢查 | ✅ |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "⚠️ 這是 upstream 同步版本。請使用 version tags 取得穩定版本。" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "❌ **不會更新 \`latest\` tag**" >> $GITHUB_STEP_SUMMARY