name: Wasm Plugin Unit Tests(GO) on: push: branches: [ main ] paths: - 'plugins/wasm-go/extensions/**' - '.github/workflows/wasm-plugin-unit-test.yml' - 'go.mod' - 'go.sum' pull_request: branches: [ "*" ] paths: - 'plugins/wasm-go/extensions/**' - '.github/workflows/wasm-plugin-unit-test.yml' - 'go.mod' - 'go.sum' env: GO111MODULE: on CGO_ENABLED: 0 GOOS: linux GOARCH: amd64 jobs: detect-changed-plugins: name: Detect Changed Plugins runs-on: ubuntu-latest outputs: changed-plugins: ${{ steps.detect.outputs.plugins }} has-changes: ${{ steps.detect.outputs.has-changes }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 # 获取完整历史用于比较 - name: Detect changed plugins id: detect run: | # 获取变更的文件列表 if [ "${{ github.event_name }}" = "pull_request" ]; then # PR模式:比较目标分支和源分支 git fetch origin ${{ github.base_ref }} CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) else # Push模式:比较当前提交和上一个提交 CHANGED_FILES=$(git diff --name-only HEAD~1 HEAD) fi echo "Changed files:" echo "$CHANGED_FILES" # 提取变更的插件名称 CHANGED_PLUGINS="" for file in $CHANGED_FILES; do if [[ $file =~ ^plugins/wasm-go/extensions/([^/]+)/ ]]; then PLUGIN_NAME="${BASH_REMATCH[1]}" if [[ ! " $CHANGED_PLUGINS " =~ " $PLUGIN_NAME " ]]; then # 修复:只在非空时添加空格 if [ -z "$CHANGED_PLUGINS" ]; then CHANGED_PLUGINS="$PLUGIN_NAME" else CHANGED_PLUGINS="$CHANGED_PLUGINS $PLUGIN_NAME" fi fi fi done # 如果没有插件变更,不触发测试 if [ -z "$CHANGED_PLUGINS" ]; then echo "No plugin changes detected, skipping tests" echo "has-changes=false" >> $GITHUB_OUTPUT echo "plugins=[]" >> $GITHUB_OUTPUT else echo "Changed plugins: $CHANGED_PLUGINS" echo "has-changes=true" >> $GITHUB_OUTPUT # 将空格分隔转换为 JSON 数组格式 PLUGINS_JSON=$(echo "$CHANGED_PLUGINS" | sed 's/ /","/g' | sed 's/^/["/' | sed 's/$/"]/') echo "PLUGINS_JSON: $PLUGINS_JSON" echo "plugins=$PLUGINS_JSON" >> $GITHUB_OUTPUT fi test: name: Test Changed Plugins runs-on: ubuntu-latest needs: detect-changed-plugins if: needs.detect-changed-plugins.outputs.has-changes == 'true' strategy: fail-fast: false matrix: plugin: ${{ fromJSON(needs.detect-changed-plugins.outputs.changed-plugins) }} steps: - name: Checkout code uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go 1.24 uses: actions/setup-go@v4 with: go-version: 1.24 cache: true - name: Install test tools run: | go install gotest.tools/gotestsum@latest # 移除gocov工具,直接使用Codecov - name: Build WASM for ${{ matrix.plugin }} working-directory: plugins/wasm-go/extensions/${{ matrix.plugin }} run: | echo "Building WASM for ${{ matrix.plugin }}..." # 检查是否存在main.go文件 export GOOS=wasip1 export GOARCH=wasm # 构建WASM文件,失败时直接退出 if ! go build -buildmode=c-shared -o main.wasm ./; then echo "❌ WASM build failed for ${{ matrix.plugin }}" exit 1 fi # 验证WASM文件是否生成 if [ ! -f "main.wasm" ]; then echo "❌ WASM file not generated for ${{ matrix.plugin }}" exit 1 fi echo "✅ WASM build successful for ${{ matrix.plugin }}" - name: Set WASM_PATH environment variable run: | echo "WASM_PATH=$(pwd)/plugins/wasm-go/extensions/${{ matrix.plugin }}/main.wasm" >> $GITHUB_ENV - name: Run tests with coverage for ${{ matrix.plugin }} working-directory: plugins/wasm-go/extensions/${{ matrix.plugin }} run: | # 检查是否存在main_test.go文件 if [ -f "main_test.go" ]; then echo "Running tests for ${{ matrix.plugin }}..." # 运行测试并生成覆盖率报告 gotestsum --junitfile ../../../../test-results-${{ matrix.plugin }}.xml \ --format standard-verbose \ --jsonfile ../../../../test-output-${{ matrix.plugin }}.json \ -- -coverprofile=coverage-${{ matrix.plugin }}.out -covermode=atomic -coverpkg=./... ./... echo "✅ Tests completed for ${{ matrix.plugin }}" else echo "No tests found for ${{ matrix.plugin }}, skipping..." # 创建空的测试结果文件 echo '' > ../../../../test-results-${{ matrix.plugin }}.xml fi - name: Upload test results for ${{ matrix.plugin }} uses: actions/upload-artifact@v4 if: always() with: name: test-results-${{ matrix.plugin }} path: | test-results-${{ matrix.plugin }}.xml test-output-${{ matrix.plugin }}.json retention-days: 30 - name: Upload coverage report for ${{ matrix.plugin }} uses: actions/upload-artifact@v4 if: always() with: name: coverage-${{ matrix.plugin }} path: plugins/wasm-go/extensions/${{ matrix.plugin }}/coverage-${{ matrix.plugin }}.out retention-days: 30 - name: Upload coverage to Codecov for ${{ matrix.plugin }} uses: codecov/codecov-action@v4 if: always() env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} with: file: plugins/wasm-go/extensions/${{ matrix.plugin }}/coverage-${{ matrix.plugin }}.out flags: wasm-go-plugin-${{ matrix.plugin }} name: codecov-${{ matrix.plugin }} fail_ci_if_error: false verbose: true test-summary: name: Test Summary & Coverage runs-on: ubuntu-latest needs: [detect-changed-plugins, test] if: always() && needs.detect-changed-plugins.outputs.has-changes == 'true' steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Go 1.24 uses: actions/setup-go@v4 with: go-version: 1.24 cache: true - name: Install required tools run: | go install github.com/wadey/gocovmerge@latest sudo apt-get update && sudo apt-get install -y bc - name: Download all test results uses: actions/download-artifact@v4 with: pattern: test-results-* merge-multiple: true path: ${{ github.workspace }} - name: Download all coverage files uses: actions/download-artifact@v4 with: pattern: coverage-* merge-multiple: true path: ${{ github.workspace }} - name: Generate comprehensive test summary run: | echo "## 🧪 Go Plugin Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY total_plugins=0 passed_plugins=0 failed_plugins=0 total_tests=0 total_failures=0 total_errors=0 echo "### 📊 Test Results by Plugin" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY for result_file in test-results-*.xml; do if [ -f "$result_file" ]; then plugin_name=$(echo "$result_file" | sed 's/test-results-\(.*\)\.xml/\1/') total_plugins=$((total_plugins + 1)) # 解析XML获取测试结果 if grep -q '> $GITHUB_STEP_SUMMARY passed_plugins=$((passed_plugins + 1)) else echo "❌ **$plugin_name**: $tests tests, $failures failures, $errors errors in ${time}s" >> $GITHUB_STEP_SUMMARY failed_plugins=$((failed_plugins + 1)) fi else echo "⚠️ **$plugin_name**: No tests found" >> $GITHUB_STEP_SUMMARY fi fi done echo "" >> $GITHUB_STEP_SUMMARY echo "### 📈 Coverage Report" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # 覆盖率门禁检查 coverage_failed=false # 解析覆盖率文件 - 使用find命令查找覆盖率文件 coverage_files=$(find ${{ github.workspace }} -name "coverage-*.out") if [ -n "$coverage_files" ]; then echo "Found coverage files:" echo "$coverage_files" fi for coverage_file in $coverage_files; do if [ -f "$coverage_file" ]; then plugin_name=$(basename "$coverage_file" | sed 's/coverage-\(.*\)\.out/\1/') # 将覆盖率文件复制到对应插件目录,避免go tool cover的模块依赖问题 echo "Processing coverage file: $coverage_file" # 检查覆盖率文件是否存在且非空 if [ -s "$coverage_file" ]; then # 将覆盖率文件复制到对应插件目录 plugin_dir="plugins/wasm-go/extensions/$plugin_name" if [ -d "$plugin_dir" ]; then cp "$coverage_file" "$plugin_dir/" cd "$plugin_dir" # 在插件目录中运行go tool cover,使用正确的模块环境 coverage_stats=$(go tool cover -func="$(basename "$coverage_file")" 2>&1 | tail -1) cd - > /dev/null # 清理复制的文件 rm -f "$plugin_dir/$(basename "$coverage_file")" else echo "Plugin directory not found: $plugin_dir" coverage_stats="" fi echo "Coverage stats result: $coverage_stats" if [ -n "$coverage_stats" ] && echo "$coverage_stats" | grep -q "%"; then # 提取覆盖率百分比 coverage_percent=$(echo "$coverage_stats" | grep -o '[0-9.]*%' | head -1 | sed 's/%//') # 确保数值有效 coverage_percent=${coverage_percent:-0} if (( $(echo "$coverage_percent > 0" | bc -l) )); then # 根据覆盖率设置颜色和图标 if (( $(echo "$coverage_percent >= 80" | bc -l) )); then coverage_icon="🟢" elif (( $(echo "$coverage_percent >= 30" | bc -l) )); then coverage_icon="🟡" else coverage_icon="🔴" coverage_failed=true fi echo "$coverage_icon **$plugin_name**: $coverage_percent%" >> $GITHUB_STEP_SUMMARY # 检查覆盖率门禁 if (( $(echo "$coverage_percent < 30" | bc -l) )); then echo "❌ **$plugin_name**: Coverage below 30% threshold!" >> $GITHUB_STEP_SUMMARY fi else echo "⚪ **$plugin_name**: No statements to cover" >> $GITHUB_STEP_SUMMARY fi else echo "⚪ **$plugin_name**: Coverage data unavailable" >> $GITHUB_STEP_SUMMARY fi else echo "⚪ **$plugin_name**: Coverage file is empty or invalid" >> $GITHUB_STEP_SUMMARY fi fi done echo "" >> $GITHUB_STEP_SUMMARY echo "📊 **Coverage reports are now available on Codecov**" >> $GITHUB_STEP_SUMMARY echo "🔗 **This Commit Coverage**: https://codecov.io/gh/${{ github.repository }}/commit/${{ github.sha }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # 覆盖率门禁检查 if [ "$coverage_failed" = true ]; then echo "### ❌ Coverage Gate Failed" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "🚫 **Coverage threshold not met**: Some plugins have coverage below 30%" >> $GITHUB_STEP_SUMMARY echo "📋 **Please improve test coverage before merging this PR**" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # 退出CI失败 echo "Coverage gate failed - some plugins below 30% threshold" exit 1 else echo "### ✅ Coverage Gate Passed" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "🎉 **All plugins meet the 30% coverage threshold**" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi echo "### 🎯 Summary" >> $GITHUB_STEP_SUMMARY echo "- **Total plugins**: $total_plugins" >> $GITHUB_STEP_SUMMARY echo "- **Passed**: $passed_plugins ✅" >> $GITHUB_STEP_SUMMARY echo "- **Failed**: $failed_plugins ❌" >> $GITHUB_STEP_SUMMARY echo "- **Total tests**: $total_tests" >> $GITHUB_STEP_SUMMARY echo "- **Total failures**: $total_failures" >> $GITHUB_STEP_SUMMARY echo "- **Total errors**: $total_errors" >> $GITHUB_STEP_SUMMARY # 如果有失败,显示详细信息 if [ $total_failures -gt 0 ] || [ $total_errors -gt 0 ]; then echo "" >> $GITHUB_STEP_SUMMARY echo "### ❌ Failed Tests Details" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Failed plugins**: $failed_plugins" >> $GITHUB_STEP_SUMMARY echo "**Total failures**: $total_failures" >> $GITHUB_STEP_SUMMARY echo "**Total errors**: $total_errors" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "📋 **View detailed logs**: [Click here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # 显示每个失败插件的详细信息 echo "#### 📊 Failed Plugin Details" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY for result_file in test-results-*.xml; do if [ -f "$result_file" ]; then plugin_name=$(echo "$result_file" | sed 's/test-results-\(.*\)\.xml/\1/') # 检查是否有失败 failures=$(grep -o 'failures="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0") errors=$(grep -o 'errors="[0-9]*"' "$result_file" | head -1 | grep -o '[0-9]*' || echo "0") # 确保数值有效 failures=${failures:-0} errors=${errors:-0} if [ "$failures" -gt 0 ] || [ "$errors" -gt 0 ]; then echo "**$plugin_name**:" >> $GITHUB_STEP_SUMMARY echo "- Failures: $failures" >> $GITHUB_STEP_SUMMARY echo "- Errors: $errors" >> $GITHUB_STEP_SUMMARY echo "- [View plugin logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi fi done fi