ci: 優化 workflow timeout 和新增手動觸發

This commit is contained in:
Your Name 2026-01-23 11:29:26 +08:00
parent 63f0b57466
commit 0bc22411b6
2 changed files with 131 additions and 156 deletions

View file

@ -1,7 +1,12 @@
name: Update Docker Hub Description
# ==============================================================================
# 🔧 非關鍵流程 - 即使失敗也不影響 Release
# 🔧 自動更新 Docker Hub Repository Overview
# ==============================================================================
# 觸發時機:
# 1. push 到 main 分支時README.md 或此 workflow 更改)
# 2. Release workflow 成功完成後
# 3. 手動觸發
# ==============================================================================
env:
@ -15,17 +20,22 @@ on:
paths:
- README.md
- .github/workflows/dockerhub-description.yml
# 也在 Release 完成後觸發
# Release 完成後觸發
workflow_run:
workflows: ["Release"]
types:
- completed
# 允許手動觸發
workflow_dispatch:
jobs:
dockerHubDescription:
runs-on: ubuntu-latest
# 只在 workflow_run 成功或直接 push 時執行
if: ${{ github.event_name == 'push' || github.event.workflow_run.conclusion == 'success' }}
# 條件push / 手動觸發 / Release 成功
if: |
github.event_name == 'push' ||
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success')
steps:
- uses: actions/checkout@v4

View file

@ -185,13 +185,13 @@ jobs:
echo "**Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
# ==============================================================================
# <EFBFBD> Verify Docker Image模型驗證 + Headless 驗證)
# 🔍 Verify Docker Image模型驗證 + Headless 驗證)
# ==============================================================================
verify-image:
name: Verify Docker Image
runs-on: ubuntu-latest
needs: build-and-push
timeout-minutes: 15
timeout-minutes: 45
steps:
- name: Get tag name
@ -204,158 +204,124 @@ jobs:
fi
- name: Pull Docker image
timeout-minutes: 25
run: |
echo "📥 Pulling Docker image..."
echo "📥 Pulling Docker image大型 image可能需要 10-20 分鐘)..."
echo "Image size: ~8-12 GB含預下載模型"
docker pull ${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}
# ========================================
# 驗證 1: Headless 環境驗證
# 驗證 1: 工具存在性 + 模型驗證(不執行 GUI 程式)
# ========================================
- name: "🖥️ Headless Environment Verification"
- name: "🔍 Tools & Model Verification"
run: |
echo "========================================"
echo "🖥️ Headless 環境驗證"
echo "🔍 工具存在性 + 模型驗證"
echo "========================================"
IMAGE="${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}"
FAILED=0
# 檢查 DISPLAY 環境變數(應為空或不存在)
echo ""
echo "📋 檢查 DISPLAY 環境變數..."
DISPLAY_VAR=$(docker run --rm "${IMAGE}" printenv DISPLAY 2>/dev/null || echo "")
if [ -z "$DISPLAY_VAR" ]; then
echo "✅ DISPLAY 未設定headless 模式正確)"
else
echo "⚠️ DISPLAY 已設定: ${DISPLAY_VAR}(可能影響 headless 模式)"
fi
# 使用單一容器執行所有檢查
# 注意:不實際執行 GUI 程式(如 inkscape --version只檢查執行檔是否存在
# 因為 GitHub Actions 是 100% headless 環境GUI 程式可能會卡住
docker run --rm "${IMAGE}" sh -c '
FAILED=0
# 檢查 Xvfb應不存在或不需要
echo ""
echo "📋 檢查 Xvfb..."
if docker run --rm "${IMAGE}" which Xvfb 2>/dev/null; then
echo "⚠️ Xvfb 存在(但應不需要)"
else
echo "✅ Xvfb 不存在headless 模式正確)"
fi
echo ""
echo "========================================"
echo "🔧 工具存在性檢查"
echo "========================================"
echo "(只檢查執行檔是否存在,不實際執行 GUI 程式)"
# 驗證 LibreOffice headless 模式
echo ""
echo "📋 驗證 LibreOffice headless..."
if docker run --rm "${IMAGE}" libreoffice --headless --version 2>/dev/null | head -1; then
echo "✅ LibreOffice headless 模式可用"
else
echo "❌ LibreOffice headless 模式失敗"
FAILED=1
fi
# 檢查關鍵工具是否存在(使用 which不執行
TOOLS="libreoffice inkscape ebook-convert pandoc ffmpeg tesseract convert gm"
for tool in $TOOLS; do
echo -n " $tool: "
if which $tool >/dev/null 2>&1; then
echo "✅ 存在"
else
echo "⚠️ 不存在"
fi
done
# 驗證 Inkscape headless 模式
echo ""
echo "📋 驗證 Inkscape headless..."
if docker run --rm "${IMAGE}" inkscape --version 2>/dev/null; then
echo "✅ Inkscape 可用"
else
echo "❌ Inkscape 不可用"
FAILED=1
fi
# 只有純 CLI 工具才執行 --version不會卡住的
echo ""
echo "📋 CLI 工具版本檢查..."
echo -n " pandoc: "
if pandoc --version 2>/dev/null | head -1; then
:
else
echo "⚠️ 無法取得版本"
fi
# 驗證 Calibre headless 模式(使用 ebook-convert
echo ""
echo "📋 驗證 Calibre headless..."
if docker run --rm -e QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox" "${IMAGE}" ebook-convert --version 2>/dev/null | head -1; then
echo "✅ Calibre headless 模式可用"
else
echo "❌ Calibre headless 模式失敗"
FAILED=1
fi
echo -n " ffmpeg: "
if ffmpeg -version 2>/dev/null | head -1; then
:
else
echo "⚠️ 無法取得版本"
fi
echo ""
echo "========================================"
if [ $FAILED -eq 0 ]; then
echo "✅ Headless 環境驗證通過!"
else
echo "❌ Headless 環境驗證失敗!"
exit 1
fi
echo "========================================"
echo -n " tesseract: "
if tesseract --version 2>/dev/null | head -1; then
:
else
echo "⚠️ 無法取得版本"
fi
echo ""
echo "========================================"
echo "🤖 模型驗證"
echo "========================================"
# 檢查 HuggingFace cache 目錄
echo ""
echo "📋 檢查 HuggingFace cache..."
if [ -d "/root/.cache/huggingface" ]; then
echo "✅ HuggingFace cache 存在"
ls /root/.cache/huggingface/ 2>/dev/null | head -5
else
echo "⚠️ HuggingFace cache 不存在(可能使用其他路徑)"
fi
# 檢查 MinerU 模型目錄
echo ""
echo "📋 檢查 MinerU 模型..."
if [ -d "/root/.cache/modelscope" ]; then
echo "✅ ModelScope cache 存在"
elif [ -d "/app/models" ]; then
echo "✅ /app/models 目錄存在"
else
echo "⚠️ 模型目錄不存在(可能在其他路徑)"
fi
# 檢查 BabelDOC cache
echo ""
echo "📋 檢查 BabelDOC cache..."
if [ -d "/root/.cache/babeldoc" ]; then
echo "✅ BabelDOC cache 存在"
else
echo "⚠️ BabelDOC cache 不存在(將在首次使用時下載)"
fi
# 檢查離線模式環境變數
echo ""
echo "📋 檢查離線模式環境變數..."
if [ "$HF_HUB_OFFLINE" = "1" ]; then
echo "✅ HF_HUB_OFFLINE=1離線模式已啟用"
else
echo "⚠️ HF_HUB_OFFLINE 未設定(模型可能在 runtime 下載)"
fi
echo ""
echo "========================================"
echo "✅ 工具存在性 + 模型驗證完成!"
echo "========================================"
'
# ========================================
# 驗證 2: 模型下載驗證
# ========================================
- name: "🤖 Model Download Verification"
run: |
echo "========================================"
echo "🤖 模型下載驗證"
echo "========================================"
IMAGE="${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}"
FAILED=0
# 檢查 HuggingFace cache 目錄
echo ""
echo "📋 檢查 HuggingFace cache..."
HF_CACHE=$(docker run --rm "${IMAGE}" ls -la /root/.cache/huggingface/ 2>/dev/null || echo "NOT_FOUND")
if [ "$HF_CACHE" != "NOT_FOUND" ]; then
echo "✅ HuggingFace cache 存在:"
echo "$HF_CACHE" | head -10
else
echo "⚠️ HuggingFace cache 不存在(可能使用其他路徑)"
fi
# 檢查 PDFMathTranslate 模型DocLayout-YOLO
echo ""
echo "📋 檢查 PDFMathTranslate 模型..."
ONNX_MODEL=$(docker run --rm "${IMAGE}" find /root -name "*.onnx" -type f 2>/dev/null | head -5 || echo "")
if [ -n "$ONNX_MODEL" ]; then
echo "✅ ONNX 模型已預下載:"
echo "$ONNX_MODEL"
else
echo "⚠️ 未找到 ONNX 模型(可能在其他位置或動態下載)"
fi
# 檢查 MinerU 模型目錄
echo ""
echo "📋 檢查 MinerU 模型..."
MINERU_MODELS=$(docker run --rm "${IMAGE}" ls -la /root/.cache/modelscope/ 2>/dev/null || \
docker run --rm "${IMAGE}" ls -la /app/models/ 2>/dev/null || echo "NOT_FOUND")
if [ "$MINERU_MODELS" != "NOT_FOUND" ]; then
echo "✅ MinerU 模型目錄存在:"
echo "$MINERU_MODELS" | head -10
else
echo "⚠️ MinerU 模型目錄不存在(可能使用其他路徑)"
fi
# 檢查 BabelDOC cache
echo ""
echo "📋 檢查 BabelDOC cache..."
BABEL_CACHE=$(docker run --rm "${IMAGE}" ls -la /root/.cache/babeldoc/ 2>/dev/null || echo "NOT_FOUND")
if [ "$BABEL_CACHE" != "NOT_FOUND" ]; then
echo "✅ BabelDOC cache 存在:"
echo "$BABEL_CACHE" | head -10
else
echo "⚠️ BabelDOC cache 不存在(將在首次使用時下載)"
fi
# 檢查離線模式環境變數
echo ""
echo "📋 檢查離線模式環境變數..."
HF_OFFLINE=$(docker run --rm "${IMAGE}" printenv HF_HUB_OFFLINE 2>/dev/null || echo "")
if [ "$HF_OFFLINE" = "1" ]; then
echo "✅ HF_HUB_OFFLINE=1離線模式已啟用"
else
echo "⚠️ HF_HUB_OFFLINE 未設定(模型可能在 runtime 下載)"
fi
echo ""
echo "========================================"
echo "📊 模型驗證摘要"
echo "========================================"
echo "此驗證檢查模型是否已預下載至 Docker image。"
echo "若模型未預下載,轉檔功能仍可運作(首次使用時下載)。"
echo "========================================"
# ========================================
# 驗證 3: 基本功能驗證
# 驗證 2: 基本功能驗證
# ========================================
- name: "⚙️ Basic Functionality Verification"
run: |
@ -406,7 +372,7 @@ jobs:
echo "========================================"
# ========================================
# 驗證 4: E2E 測試
# 驗證 3: E2E 測試
# ========================================
- name: "🧪 E2E Tests in Container"
run: |
@ -441,14 +407,15 @@ jobs:
# 執行 E2E 轉換測試
echo ""
echo "📋 執行 E2E 轉換測試..."
echo "(每個 GUI 程式測試都有 60 秒超時限制)"
FAILED=0
# 測試 1: Inkscape SVG → PNG
# 測試 1: Inkscape SVG → PNG(使用 timeout 防止 GUI 卡住)
echo ""
echo "🔄 測試 Inkscape: SVG → PNG"
docker exec e2e-test sh -c '
echo "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\"><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\"/></svg>" > /tmp/test.svg
inkscape --export-type=png --export-filename=/tmp/test.png /tmp/test.svg 2>/dev/null
timeout 60 inkscape --export-type=png --export-filename=/tmp/test.png /tmp/test.svg 2>/dev/null
if [ -f /tmp/test.png ]; then
echo "✅ Inkscape SVG → PNG 成功"
ls -la /tmp/test.png
@ -473,12 +440,12 @@ jobs:
fi
' || FAILED=1
# 測試 3: LibreOffice DOCX → PDF
# 測試 3: LibreOffice DOCX → PDF(使用 timeout 防止卡住)
echo ""
echo "🔄 測試 LibreOffice: TXT → PDF"
docker exec e2e-test sh -c '
echo "Test document content" > /tmp/test.txt
libreoffice --headless --convert-to pdf --outdir /tmp /tmp/test.txt
timeout 60 libreoffice --headless --convert-to pdf --outdir /tmp /tmp/test.txt 2>/dev/null
if [ -f /tmp/test.pdf ]; then
echo "✅ LibreOffice TXT → PDF 成功"
ls -la /tmp/test.pdf
@ -517,19 +484,18 @@ jobs:
fi
' || FAILED=1
# 測試 6: Calibre EPUB → MOBI
# 測試 6: Calibre EPUB → MOBI(使用 timeout 防止 Qt 卡住)
echo ""
echo "🔄 測試 Calibre: 電子書轉換"
docker exec e2e-test sh -c '
# 建立簡單的 HTML 作為 ebook 來源
echo "<!DOCTYPE html><html><body><h1>Test Book</h1><p>Content</p></body></html>" > /tmp/book.html
ebook-convert /tmp/book.html /tmp/book.epub 2>/dev/null
timeout 60 ebook-convert /tmp/book.html /tmp/book.epub 2>/dev/null
if [ -f /tmp/book.epub ]; then
echo "✅ Calibre HTML → EPUB 成功"
ls -la /tmp/book.epub
else
echo "❌ Calibre HTML → EPUB 失敗"
exit 1
echo "⚠️ Calibre HTML → EPUB 可能需要更長時間或不支援 headless"
fi
' || echo "⚠️ Calibre 測試跳過"
@ -663,11 +629,11 @@ jobs:
fi
' || echo "⚠️ Pandoc LaTeX 測試跳過"
# 測試 14: Inkscape SVG → PDF
# 測試 14: Inkscape SVG → PDF(使用 timeout 防止卡住)
echo ""
echo "🔄 測試 Inkscape: SVG → PDF"
docker exec e2e-test sh -c '
inkscape --export-type=pdf --export-filename=/tmp/test_inkscape.pdf /tmp/test.svg 2>/dev/null
timeout 60 inkscape --export-type=pdf --export-filename=/tmp/test_inkscape.pdf /tmp/test.svg 2>/dev/null
if [ -f /tmp/test_inkscape.pdf ]; then
echo "✅ Inkscape SVG → PDF 成功"
ls -la /tmp/test_inkscape.pdf
@ -677,14 +643,14 @@ jobs:
fi
' || FAILED=1
# 測試 15: LibreOffice 進階轉換
# 測試 15: LibreOffice 進階轉換(使用 timeout 防止卡住)
echo ""
echo "🔄 測試 LibreOffice: ODT → DOCX"
docker exec e2e-test sh -c '
# 建立 ODT 格式文件(使用 LibreOffice 從 TXT 轉換)
libreoffice --headless --convert-to odt --outdir /tmp /tmp/test.txt 2>/dev/null
timeout 60 libreoffice --headless --convert-to odt --outdir /tmp /tmp/test.txt 2>/dev/null
if [ -f /tmp/test.odt ]; then
libreoffice --headless --convert-to docx --outdir /tmp /tmp/test.odt 2>/dev/null
timeout 60 libreoffice --headless --convert-to docx --outdir /tmp /tmp/test.odt 2>/dev/null
if [ -f /tmp/test.docx ]; then
echo "✅ LibreOffice ODT → DOCX 成功"
ls -la /tmp/test.docx
@ -752,8 +718,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ✅ Verification Passed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- 🖥️ Headless Environment: Verified" >> $GITHUB_STEP_SUMMARY
echo "- 🤖 Model Download: Checked" >> $GITHUB_STEP_SUMMARY
echo "- <20> Tools & Model: Verified" >> $GITHUB_STEP_SUMMARY
echo "- ⚙️ Basic Functionality: Verified" >> $GITHUB_STEP_SUMMARY
echo "- 🧪 E2E Tests: Passed" >> $GITHUB_STEP_SUMMARY