# ============================================================================== # Upstream Sync Build + Smoke Test # 功能: # 1. dev 分支有 push 時自動觸發 # 2. 建構 Docker image(僅 amd64 用於測試) # 3. 執行 smoke test(10 分鐘內完成) # 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: 最小轉換測試 (txt → pdf) # ======================================== - name: "Test 3: 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 4: API 端點檢查 # ======================================== - name: "Test 4: 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 "| 最小轉換測試 | ✅ 通過 |" >> $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 "| 最小轉換測試 | ✅ |" >> $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