566 lines
22 KiB
YAML
566 lines
22 KiB
YAML
name: Release
|
||
|
||
on:
|
||
push:
|
||
tags:
|
||
- "v*.*.*"
|
||
# 允許手動觸發
|
||
workflow_dispatch:
|
||
inputs:
|
||
tag:
|
||
description: "Tag to release (e.g., v0.1.13)"
|
||
required: true
|
||
type: string
|
||
|
||
env:
|
||
DOCKER_IMAGE: convertx/convertx-cn
|
||
|
||
jobs:
|
||
# ==============================================================================
|
||
# 🐳 Build and Push Docker Image(關鍵流程)
|
||
# ==============================================================================
|
||
build-and-push:
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: read
|
||
packages: write
|
||
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
|
||
# ========================================
|
||
# 清理磁碟空間(解決 no space left on device)
|
||
# ========================================
|
||
# 🔥 GitHub Actions Runner 只有約 14GB 可用空間
|
||
# 大型模型 + Multi-Arch build 需要清理更多預裝軟體
|
||
# ========================================
|
||
- name: Free disk space (aggressive)
|
||
run: |
|
||
echo "🧹 Aggressive disk cleanup for large model builds..."
|
||
echo "========================================"
|
||
echo "📊 初始磁碟空間:"
|
||
df -h /
|
||
echo "========================================"
|
||
|
||
# ========================================
|
||
# 移除大型預裝軟體(約可釋放 30-40GB)
|
||
# ========================================
|
||
echo "🗑️ 移除預裝開發工具..."
|
||
|
||
# .NET SDK(約 2-3GB)
|
||
sudo rm -rf /usr/share/dotnet || true
|
||
|
||
# Android SDK(約 10-15GB)- 最大宗!
|
||
sudo rm -rf /usr/local/lib/android || true
|
||
|
||
# Haskell/GHC(約 1GB)
|
||
sudo rm -rf /opt/ghc || true
|
||
|
||
# CodeQL(約 1GB)
|
||
sudo rm -rf /opt/hostedtoolcache/CodeQL || true
|
||
|
||
# Boost(約 500MB)
|
||
sudo rm -rf /usr/local/share/boost || true
|
||
|
||
# Swift(約 1.5GB)
|
||
sudo rm -rf /usr/share/swift || true
|
||
|
||
# Hosted Tool Cache(約 5-8GB)
|
||
sudo rm -rf /opt/hostedtoolcache || true
|
||
|
||
# Azure CLI(約 500MB)
|
||
sudo rm -rf /usr/share/az_* || true
|
||
sudo rm -rf /opt/az || true
|
||
|
||
# Google Cloud SDK(約 500MB)
|
||
sudo rm -rf /usr/lib/google-cloud-sdk || true
|
||
|
||
# PowerShell(約 200MB)
|
||
sudo rm -rf /usr/local/share/powershell || true
|
||
|
||
# Miniconda(約 500MB)
|
||
sudo rm -rf /usr/share/miniconda || true
|
||
|
||
# ========================================
|
||
# 清理系統 cache
|
||
# ========================================
|
||
echo "🗑️ 清理系統 cache..."
|
||
|
||
# apt cache
|
||
sudo apt-get clean || true
|
||
sudo apt-get autoremove -y || true
|
||
sudo rm -rf /var/lib/apt/lists/* || true
|
||
|
||
# npm/yarn global cache
|
||
sudo rm -rf /usr/local/share/.cache || true
|
||
|
||
# ========================================
|
||
# 清理 Docker 舊資料
|
||
# ========================================
|
||
echo "🗑️ 清理 Docker cache..."
|
||
docker system prune -af --volumes || true
|
||
|
||
# 清理 BuildKit cache
|
||
sudo rm -rf /var/lib/docker/buildkit || true
|
||
|
||
echo "========================================"
|
||
echo "📊 清理後磁碟空間:"
|
||
df -h /
|
||
echo "========================================"
|
||
|
||
- name: Get tag name
|
||
id: tag
|
||
run: |
|
||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||
echo "version=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Set up QEMU
|
||
uses: docker/setup-qemu-action@v3
|
||
|
||
# ========================================
|
||
# 設定 Docker Buildx(針對大型模型優化)
|
||
# ========================================
|
||
- name: Set up Docker Buildx
|
||
uses: docker/setup-buildx-action@v3
|
||
with:
|
||
# 🔥 使用 docker-container driver 以獲得更好的 cache 控制
|
||
driver-opts: |
|
||
image=moby/buildkit:latest
|
||
network=host
|
||
|
||
- name: Login to Docker Hub
|
||
uses: docker/login-action@v3
|
||
with:
|
||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||
|
||
- name: Login to GitHub Container Registry
|
||
uses: docker/login-action@v3
|
||
with:
|
||
registry: ghcr.io
|
||
username: ${{ github.actor }}
|
||
password: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
# ========================================
|
||
# Build and Push(針對大型模型優化)
|
||
# ========================================
|
||
# 🔥 注意事項:
|
||
# - 使用 registry cache 而非 GHA cache(避免 10GB 限制)
|
||
# - 啟用 zstd compression 減少傳輸量和儲存空間
|
||
# - Multi-arch build 需要更多磁碟空間,已在上方清理
|
||
# ========================================
|
||
- name: Build and push Docker image
|
||
uses: docker/build-push-action@v6
|
||
with:
|
||
context: .
|
||
push: true
|
||
tags: |
|
||
${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}
|
||
${{ env.DOCKER_IMAGE }}:latest
|
||
platforms: linux/amd64,linux/arm64
|
||
# 🔥 使用 registry cache 取代 GHA cache
|
||
# registry cache 沒有 10GB 限制,更適合大型模型
|
||
cache-from: type=registry,ref=${{ env.DOCKER_IMAGE }}:buildcache
|
||
cache-to: type=registry,ref=${{ env.DOCKER_IMAGE }}:buildcache,mode=max,compression=zstd
|
||
# 啟用壓縮減少 image 大小
|
||
outputs: type=image,compression=zstd,compression-level=3
|
||
# 設定 build 參數
|
||
build-args: |
|
||
BUILDKIT_INLINE_CACHE=1
|
||
|
||
- name: Docker Build Summary
|
||
run: |
|
||
echo "## 🐳 Docker Image Published" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Repository:** \`${{ env.DOCKER_IMAGE }}\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
|
||
echo "- \`${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "- \`${{ env.DOCKER_IMAGE }}:latest\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Platforms:** linux/amd64, linux/arm64" >> $GITHUB_STEP_SUMMARY
|
||
|
||
# ==============================================================================
|
||
# 🔍 Verify Docker Image(模型驗證 + Headless 驗證)
|
||
# ==============================================================================
|
||
verify-image:
|
||
name: Verify Docker Image
|
||
runs-on: ubuntu-latest
|
||
needs: build-and-push
|
||
timeout-minutes: 45
|
||
|
||
steps:
|
||
- name: Get tag name
|
||
id: tag
|
||
run: |
|
||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||
echo "version=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Pull Docker image
|
||
timeout-minutes: 25
|
||
run: |
|
||
echo "📥 Pulling Docker image(大型 image,可能需要 10-20 分鐘)..."
|
||
echo "Image size: ~8-12 GB(含預下載模型)"
|
||
docker pull ${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}
|
||
|
||
# ========================================
|
||
# 驗證 1: 工具存在性 + 版本檢查(使用 xvfb 解決 GUI 問題)
|
||
# ========================================
|
||
- name: "🔍 Tools & Model Verification"
|
||
timeout-minutes: 8
|
||
continue-on-error: true # 🔥 版本檢查失敗不應阻擋後續 E2E 測試
|
||
run: |
|
||
echo "========================================"
|
||
echo "🔍 工具存在性 + 模型驗證"
|
||
echo "========================================"
|
||
|
||
IMAGE="${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}"
|
||
|
||
# 🔥 關鍵修復:
|
||
# 1. 為每個 GUI 工具版本檢查添加 timeout 防止無限掛起
|
||
# 2. 使用 timeout 命令限制每個工具的執行時間
|
||
# 3. 增加整體 timeout-minutes 從 5 到 8 分鐘
|
||
docker run --rm "${IMAGE}" sh -c '
|
||
echo ""
|
||
echo "========================================"
|
||
echo "🔧 CLI 工具版本檢查"
|
||
echo "========================================"
|
||
|
||
# 純 CLI 工具 - 直接執行
|
||
echo "ConvertX $(cat /app/package.json 2>/dev/null | grep version | head -1 | cut -d\" -f4)"
|
||
echo "Bun $(bun --version 2>/dev/null || echo "N/A")"
|
||
pandoc --version 2>/dev/null | head -1 || echo "pandoc: N/A"
|
||
ffmpeg -version 2>/dev/null | head -1 || echo "ffmpeg: N/A"
|
||
tesseract --version 2>&1 | head -1 || echo "tesseract: N/A"
|
||
vips --version 2>/dev/null || echo "vips: N/A"
|
||
gm -version 2>/dev/null | head -1 || echo "GraphicsMagick: N/A"
|
||
resvg --version 2>/dev/null || echo "resvg: N/A"
|
||
potrace --version 2>/dev/null | head -1 || echo "potrace: N/A"
|
||
dasel --version 2>/dev/null || echo "dasel: N/A"
|
||
djxl --version 2>&1 | head -1 || echo "djxl: N/A"
|
||
deark -version 2>/dev/null | head -1 || echo "deark: N/A"
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "🖥️ GUI 工具版本檢查(使用 xvfb-run + timeout)"
|
||
echo "========================================"
|
||
|
||
# GUI 工具 - 使用 timeout + xvfb-run 防止掛起
|
||
# timeout 60 秒,超過就跳過該工具
|
||
echo -n "Inkscape: "
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" inkscape --version 2>/dev/null || echo "N/A (timeout or error)"
|
||
|
||
echo -n "Calibre: "
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" ebook-convert --version 2>/dev/null | head -1 || echo "N/A (timeout or error)"
|
||
|
||
echo -n "LibreOffice: "
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" libreoffice --version 2>/dev/null || echo "N/A (timeout or error)"
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "🤖 模型目錄檢查"
|
||
echo "========================================"
|
||
|
||
echo -n " HuggingFace cache: "
|
||
[ -d "/root/.cache/huggingface" ] && echo "✅ 存在" || echo "⚠️ 不存在"
|
||
|
||
echo -n " ModelScope cache: "
|
||
[ -d "/root/.cache/modelscope" ] && echo "✅ 存在" || echo "⚠️ 不存在"
|
||
|
||
echo -n " BabelDOC cache: "
|
||
[ -d "/root/.cache/babeldoc" ] && echo "✅ 存在" || echo "⚠️ 不存在"
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "✅ 工具驗證完成!"
|
||
echo "========================================"
|
||
'
|
||
|
||
# ========================================
|
||
# 驗證 2: 啟動容器並檢查健康狀態
|
||
# ========================================
|
||
- name: "⚙️ Start Container & Health Check"
|
||
timeout-minutes: 3
|
||
run: |
|
||
echo "========================================"
|
||
echo "⚙️ 啟動容器並檢查健康狀態"
|
||
echo "========================================"
|
||
|
||
IMAGE="${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}"
|
||
|
||
# 啟動容器
|
||
echo "🚀 啟動容器..."
|
||
docker run -d --name verify-test -p 3000:3000 "${IMAGE}"
|
||
|
||
# 等待啟動
|
||
echo "⏳ 等待容器啟動..."
|
||
for i in {1..90}; do
|
||
if docker exec verify-test curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
|
||
echo "✅ 容器在 ${i} 秒內啟動成功"
|
||
break
|
||
fi
|
||
if [ $i -eq 90 ]; then
|
||
echo "❌ 容器啟動超時"
|
||
docker logs verify-test
|
||
docker rm -f verify-test
|
||
exit 1
|
||
fi
|
||
sleep 1
|
||
done
|
||
|
||
# 顯示容器日誌
|
||
echo ""
|
||
echo "📋 容器啟動日誌:"
|
||
docker logs verify-test 2>&1 | tail -20
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "✅ 容器健康檢查通過!"
|
||
echo "========================================"
|
||
|
||
# ========================================
|
||
# 驗證 3: E2E 轉換測試(模擬真實用戶操作)
|
||
# ========================================
|
||
- name: "🧪 E2E Tests in Container"
|
||
timeout-minutes: 15
|
||
run: |
|
||
echo "========================================"
|
||
echo "🧪 E2E 轉換測試(模擬真實用戶操作)"
|
||
echo "========================================"
|
||
|
||
# 首先確認容器健康
|
||
echo "🔍 確認服務健康狀態..."
|
||
for i in {1..30}; do
|
||
if curl -sf http://localhost:3000/healthcheck > /dev/null 2>&1; then
|
||
echo "✅ 服務健康"
|
||
break
|
||
fi
|
||
if [ $i -eq 30 ]; then
|
||
echo "❌ 服務不健康"
|
||
docker logs verify-test 2>&1 | tail -30
|
||
exit 1
|
||
fi
|
||
sleep 1
|
||
done
|
||
|
||
# 定義測試結果追蹤
|
||
TOTAL_TESTS=0
|
||
PASSED_TESTS=0
|
||
FAILED_TESTS=0
|
||
|
||
run_test() {
|
||
local name="$1"
|
||
local cmd="$2"
|
||
TOTAL_TESTS=$((TOTAL_TESTS + 1))
|
||
echo ""
|
||
echo "🔄 測試: $name"
|
||
if docker exec verify-test bash -c "$cmd" 2>&1; then
|
||
echo "✅ $name 成功"
|
||
PASSED_TESTS=$((PASSED_TESTS + 1))
|
||
return 0
|
||
else
|
||
echo "❌ $name 失敗"
|
||
FAILED_TESTS=$((FAILED_TESTS + 1))
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "📋 測試工具轉換功能"
|
||
echo "========================================"
|
||
|
||
# 1. Pandoc: Markdown → HTML (純 CLI)
|
||
run_test "Pandoc: Markdown → HTML" '
|
||
echo "# Test Document" > /tmp/test.md
|
||
echo "" >> /tmp/test.md
|
||
echo "Hello **world**" >> /tmp/test.md
|
||
pandoc /tmp/test.md -o /tmp/test.html
|
||
[ -s /tmp/test.html ] && cat /tmp/test.html
|
||
' || true
|
||
|
||
# 2. FFmpeg: 音頻生成 (純 CLI)
|
||
run_test "FFmpeg: 音頻生成" '
|
||
ffmpeg -f lavfi -i "sine=frequency=440:duration=1" -y /tmp/test.wav 2>/dev/null
|
||
[ -s /tmp/test.wav ] && ls -la /tmp/test.wav
|
||
' || true
|
||
|
||
# 3. FFmpeg: 影片生成 (純 CLI)
|
||
run_test "FFmpeg: 影片生成" '
|
||
ffmpeg -f lavfi -i color=c=blue:s=320x240:d=1 -y /tmp/test_video.mp4 2>/dev/null
|
||
[ -s /tmp/test_video.mp4 ] && ls -la /tmp/test_video.mp4
|
||
' || true
|
||
|
||
# 4. Resvg: SVG → PNG (純 CLI)
|
||
run_test "Resvg: SVG → PNG" '
|
||
echo "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"50\" height=\"50\"><rect fill=\"green\" width=\"50\" height=\"50\"/></svg>" > /tmp/resvg.svg
|
||
resvg /tmp/resvg.svg /tmp/resvg.png 2>/dev/null
|
||
[ -s /tmp/resvg.png ] && ls -la /tmp/resvg.png
|
||
' || true
|
||
|
||
# 5. Dasel: JSON → YAML (純 CLI)
|
||
run_test "Dasel: JSON → YAML" '
|
||
echo "{\"name\":\"test\",\"value\":123}" > /tmp/test.json
|
||
dasel -f /tmp/test.json -w yaml > /tmp/test.yaml 2>/dev/null
|
||
[ -s /tmp/test.yaml ] && cat /tmp/test.yaml
|
||
' || true
|
||
|
||
# 6. Tesseract: OCR (需要 ImageMagick 生成測試圖片)
|
||
run_test "Tesseract: OCR" '
|
||
convert -size 200x50 xc:white -font DejaVu-Sans -pointsize 20 -fill black -annotate +10+35 "Hello OCR" /tmp/ocr.png 2>/dev/null
|
||
tesseract /tmp/ocr.png /tmp/ocr 2>/dev/null
|
||
[ -s /tmp/ocr.txt ] && cat /tmp/ocr.txt
|
||
' || true
|
||
|
||
# 7. Inkscape: SVG → PNG (需要 xvfb)
|
||
run_test "Inkscape: SVG → PNG" '
|
||
echo "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"100\" height=\"100\"><circle cx=\"50\" cy=\"50\" r=\"40\" fill=\"red\"/></svg>" > /tmp/ink.svg
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" inkscape --export-type=png --export-filename=/tmp/ink.png /tmp/ink.svg 2>&1 || true
|
||
[ -s /tmp/ink.png ] && ls -la /tmp/ink.png
|
||
' || true
|
||
|
||
# 8. LibreOffice: TXT → PDF (需要 xvfb)
|
||
run_test "LibreOffice: TXT → PDF" '
|
||
echo "Test document for LibreOffice conversion" > /tmp/libre.txt
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" libreoffice --headless --convert-to pdf --outdir /tmp /tmp/libre.txt 2>&1 || true
|
||
[ -s /tmp/libre.pdf ] && ls -la /tmp/libre.pdf
|
||
' || true
|
||
|
||
# 9. Calibre: HTML → EPUB (需要 xvfb)
|
||
run_test "Calibre: HTML → EPUB" '
|
||
echo "<!DOCTYPE html><html><body><h1>Test Book</h1><p>Content here</p></body></html>" > /tmp/book.html
|
||
timeout 60 xvfb-run -a --server-args="-screen 0 1024x768x24" ebook-convert /tmp/book.html /tmp/book.epub 2>&1 || true
|
||
[ -s /tmp/book.epub ] && ls -la /tmp/book.epub
|
||
' || true
|
||
|
||
echo ""
|
||
echo "========================================"
|
||
echo "📋 測試 API 端點"
|
||
echo "========================================"
|
||
|
||
# 10. Healthcheck API
|
||
run_test "API: Healthcheck" '
|
||
response=$(curl -sf http://localhost:3000/healthcheck)
|
||
echo "Response: $response"
|
||
[ -n "$response" ]
|
||
' || true
|
||
|
||
# 11. Converters API
|
||
run_test "API: Converters 列表" '
|
||
response=$(curl -sf http://localhost:3000/converters 2>/dev/null | head -c 500)
|
||
echo "Response (前500字符): $response"
|
||
[ -n "$response" ]
|
||
' || true
|
||
|
||
# 12. 主頁面
|
||
run_test "API: 主頁面載入" '
|
||
status=$(curl -sf -o /dev/null -w "%{http_code}" http://localhost:3000/)
|
||
echo "HTTP Status: $status"
|
||
[ "$status" = "200" ] || [ "$status" = "302" ]
|
||
' || true
|
||
|
||
# 測試摘要
|
||
echo ""
|
||
echo "========================================"
|
||
echo "📊 E2E 測試摘要"
|
||
echo "========================================"
|
||
echo "總測試數: $TOTAL_TESTS"
|
||
echo "通過: $PASSED_TESTS"
|
||
echo "失敗: $FAILED_TESTS"
|
||
echo "========================================"
|
||
|
||
# 計算通過率
|
||
if [ $TOTAL_TESTS -gt 0 ]; then
|
||
PASS_RATE=$((PASSED_TESTS * 100 / TOTAL_TESTS))
|
||
echo "通過率: ${PASS_RATE}%"
|
||
|
||
# 至少 70% 通過才算成功
|
||
if [ $PASS_RATE -ge 70 ]; then
|
||
echo "✅ E2E 測試通過 (>= 70% 通過率)"
|
||
else
|
||
echo "❌ E2E 測試失敗 (< 70% 通過率)"
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "⚠️ 沒有執行任何測試"
|
||
fi
|
||
|
||
# ========================================
|
||
# 清理驗證容器
|
||
# ========================================
|
||
- name: "🧹 Cleanup Verification Containers"
|
||
if: always()
|
||
run: |
|
||
docker rm -f verify-test 2>/dev/null || true
|
||
|
||
- name: Verification Summary
|
||
run: |
|
||
echo "## 🔍 Image Verification Results" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "**Image:** \`${{ env.DOCKER_IMAGE }}:${{ steps.tag.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $GITHUB_STEP_SUMMARY
|
||
echo "### ✅ Verification Passed" >> $GITHUB_STEP_SUMMARY
|
||
echo "" >> $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
|
||
|
||
# ==============================================================================
|
||
# 📦 Create GitHub Release
|
||
# ==============================================================================
|
||
create-release:
|
||
runs-on: ubuntu-latest
|
||
needs: [build-and-push, verify-image]
|
||
permissions:
|
||
contents: write
|
||
|
||
steps:
|
||
- name: Checkout repository
|
||
uses: actions/checkout@v4
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- name: Get tag name
|
||
id: tag
|
||
run: |
|
||
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
|
||
echo "version=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT
|
||
else
|
||
echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||
fi
|
||
|
||
- name: Generate changelog
|
||
id: changelog
|
||
run: |
|
||
# Get previous tag
|
||
PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
|
||
|
||
if [ -z "$PREVIOUS_TAG" ]; then
|
||
# No previous tag, get all commits
|
||
CHANGELOG=$(git log --pretty=format:"- %s (%h)" HEAD)
|
||
else
|
||
# Get commits between previous tag and current
|
||
CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREVIOUS_TAG}..HEAD)
|
||
fi
|
||
|
||
# Write to file to preserve newlines
|
||
echo "$CHANGELOG" > changelog.txt
|
||
|
||
- name: Create GitHub Release
|
||
uses: softprops/action-gh-release@v2
|
||
with:
|
||
name: ${{ steps.tag.outputs.version }}
|
||
tag_name: ${{ steps.tag.outputs.version }}
|
||
body_path: changelog.txt
|
||
generate_release_notes: true
|
||
draft: false
|
||
prerelease: false
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|