@@ -696,6 +696,11 @@ jobs:
696696 --input "$COVERAGE_FILE" \
697697 --output "$OUTPUT_DIR"; then
698698 echo "✅ Main coverage processing completed successfully"
699+
700+ # Copy raw coverage file for main download
701+ echo "📥 Copying coverage.out for main download..."
702+ cp "$COVERAGE_FILE" "$OUTPUT_DIR/coverage.out"
703+ echo "✅ coverage.out copied to main directory"
699704 else
700705 echo "❌ Main coverage processing failed"
701706 exit 1
@@ -791,6 +796,11 @@ jobs:
791796 --input "$COVERAGE_FILE" \
792797 --output "$BRANCH_OUTPUT_DIR"; then
793798 echo "✅ Branch-specific coverage processing completed successfully"
799+
800+ # Copy raw coverage file for branch download
801+ echo "📥 Copying coverage.out for branch download..."
802+ cp "$COVERAGE_FILE" "$BRANCH_OUTPUT_DIR/coverage.out"
803+ echo "✅ coverage.out copied to branch directory"
794804 else
795805 echo "❌ Branch-specific coverage processing failed"
796806 exit 1
@@ -870,6 +880,78 @@ jobs:
870880
871881 echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
872882
883+ # --------------------------------------------------------------------
884+ # Enforce Coverage Threshold
885+ # Fails the build if coverage drops below GO_COVERAGE_THRESHOLD
886+ # Exclusions are already applied during coverage generation
887+ # --------------------------------------------------------------------
888+ - name : 🎯 Enforce Coverage Threshold
889+ if : env.GO_COVERAGE_THRESHOLD != '' && env.GO_COVERAGE_THRESHOLD != '0' && env.GO_COVERAGE_THRESHOLD != '0.0'
890+ run : |
891+ echo "🎯 Enforcing coverage threshold..."
892+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
893+
894+ THRESHOLD="${{ env.GO_COVERAGE_THRESHOLD }}"
895+ echo "📊 Coverage threshold: ${THRESHOLD}%"
896+
897+ # Find coverage file
898+ REPO_ROOT="$(pwd)"
899+ COVERAGE_FILE=""
900+ COVERAGE_LOCATIONS=(
901+ "$REPO_ROOT/coverage-artifacts/coverage-data/${{ inputs.coverage-file }}"
902+ "$REPO_ROOT/coverage-artifacts/${{ inputs.coverage-file }}"
903+ "$REPO_ROOT/${{ inputs.coverage-file }}"
904+ )
905+
906+ for location in "${COVERAGE_LOCATIONS[@]}"; do
907+ if [[ -f "$location" ]]; then
908+ COVERAGE_FILE="$location"
909+ break
910+ fi
911+ done
912+
913+ if [[ -z "$COVERAGE_FILE" ]]; then
914+ echo "⚠️ Coverage file not found for threshold check"
915+ echo "🔍 Searched in:"
916+ for location in "${COVERAGE_LOCATIONS[@]}"; do
917+ echo " - $location"
918+ done
919+ echo "❌ Cannot enforce threshold without coverage data"
920+ exit 1
921+ fi
922+
923+ echo "📄 Coverage file: $COVERAGE_FILE"
924+ echo ""
925+
926+ # Use go-coverage parse to check threshold
927+ # This command returns non-zero exit code if coverage is below threshold
928+ echo "🔍 Checking coverage against threshold..."
929+ if "$GO_COVERAGE_BINARY" parse \
930+ --file "$COVERAGE_FILE" \
931+ --threshold "$THRESHOLD"; then
932+ echo ""
933+ echo "✅ Coverage threshold check PASSED"
934+ else
935+ EXIT_CODE=$?
936+ echo ""
937+ echo "❌ Coverage threshold check FAILED"
938+ echo ""
939+ echo "🚨 BUILD FAILURE: Coverage is below the required threshold of ${THRESHOLD}%"
940+ echo ""
941+ echo "📝 To fix this:"
942+ echo " 1. Add more tests to increase coverage"
943+ echo " 2. Or adjust GO_COVERAGE_THRESHOLD in .env.base/.env.custom"
944+ echo ""
945+ echo "📊 Coverage exclusions (applied during test generation):"
946+ echo " - GO_COVERAGE_EXCLUDE_PATHS: ${{ env.GO_COVERAGE_EXCLUDE_PATHS }}"
947+ echo " - GO_COVERAGE_EXCLUDE_FILES: ${{ env.GO_COVERAGE_EXCLUDE_FILES }}"
948+ echo " - GO_COVERAGE_EXCLUDE_TESTS: ${{ env.GO_COVERAGE_EXCLUDE_TESTS }}"
949+ echo " - GO_COVERAGE_EXCLUDE_GENERATED: ${{ env.GO_COVERAGE_EXCLUDE_GENERATED }}"
950+ exit $EXIT_CODE
951+ fi
952+
953+ echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
954+
873955 - name : 📈 Record coverage history
874956 # Record history for all branches to enable trend tracking
875957 if : github.event_name == 'push'
@@ -1143,6 +1225,7 @@ jobs:
11431225 "coverage-flat.svg"
11441226 "coverage-flat-square.svg"
11451227 "coverage-for-the-badge.svg"
1228+ "coverage.out"
11461229 )
11471230
11481231 # Selectively copy coverage files to avoid nested directory structures
@@ -1198,6 +1281,7 @@ jobs:
11981281 "coverage-flat-square.svg"
11991282 "coverage-for-the-badge.svg"
12001283 "coverage.html"
1284+ "coverage.out"
12011285 "index.html"
12021286 "dashboard.html"
12031287 "coverage-data.json"
@@ -1666,7 +1750,7 @@ jobs:
16661750 echo "📋 Updating root coverage files for main branch (with filtering)..."
16671751
16681752 # Define allowed root files explicitly
1669- ALLOWED_ROOT_FILES=("index.html" "coverage.html" "coverage.svg" "coverage-flat.svg" "coverage-flat-square.svg" "coverage-for-the-badge.svg" ".nojekyll" "data" "assets")
1753+ ALLOWED_ROOT_FILES=("index.html" "coverage.html" "coverage.svg" "coverage-flat.svg" "coverage-flat-square.svg" "coverage-for-the-badge.svg" "coverage.out" " .nojekyll" "data" "assets")
16701754
16711755 # Copy only allowed root files
16721756 for file in "${ALLOWED_ROOT_FILES[@]}"; do
@@ -1731,7 +1815,7 @@ jobs:
17311815 rm -rf "$TEMP_STAGING"/*
17321816
17331817 # Define allowed branch files
1734- ALLOWED_BRANCH_FILES=("index.html" "coverage.html" "coverage.svg" "coverage-flat.svg" "coverage-flat-square.svg" "coverage-for-the-badge.svg" "data" "assets")
1818+ ALLOWED_BRANCH_FILES=("index.html" "coverage.html" "coverage.svg" "coverage-flat.svg" "coverage-flat-square.svg" "coverage-for-the-badge.svg" "coverage.out" " data" "assets")
17351819
17361820 # Copy branch-specific files from deployment directory to staging first
17371821 if [[ -d "$DEPLOY_DIR/coverage/branch/$BRANCH_NAME" ]]; then
0 commit comments