name: CI on: push: branches: [ "master", "develop" ] tags: - "v*.*.*" pull_request: branches: [ "master", "develop" ] jobs: test: name: Test runs-on: ubuntu-latest permissions: contents: write strategy: matrix: go: - 1.21.x - 1.22.x - 1.23.x - 1.24.x steps: - uses: actions/checkout@v4 - name: Set up Go ${{ matrix.go }} uses: actions/setup-go@v5 with: go-version: ${{ matrix.go }} check-latest: true cache-dependency-path: "**/*.sum" - name: Download dependencies run: go mod download && echo "Download successful" || go mod tidy && echo "Tidy successful" || return 1 - name: Verify dependencies run: go mod verify - name: Build run: go build -v ./... - name: Run tests with enhanced reporting id: test run: | echo "## ๐Ÿ”ง Test Environment" >> $GITHUB_STEP_SUMMARY echo "- **Go Version:** ${{ matrix.go }}" >> $GITHUB_STEP_SUMMARY echo "- **OS:** ubuntu-latest" >> $GITHUB_STEP_SUMMARY echo "- **Timestamp:** $(date -u)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Running tests with coverage..." go test -v -race -coverprofile=coverage.out ./... 2>&1 | tee test-output.log # Extract test results for summary TEST_STATUS=$? TOTAL_TESTS=$(grep -c "=== RUN" test-output.log || echo "0") PASSED_TESTS=$(grep -c "--- PASS:" test-output.log || echo "0") FAILED_TESTS=$(grep -c "--- FAIL:" test-output.log || echo "0") SKIPPED_TESTS=$(grep -c "--- SKIP:" test-output.log || echo "0") # Generate test summary echo "## ๐Ÿงช Test Results (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Total Tests | $TOTAL_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Passed | โœ… $PASSED_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Failed | โŒ $FAILED_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Skipped | โญ๏ธ $SKIPPED_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Status | $([ $TEST_STATUS -eq 0 ] && echo "โœ… PASSED" || echo "โŒ FAILED") |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Add package breakdown echo "### ๐Ÿ“ฆ Package Test Results" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Package | Status |" >> $GITHUB_STEP_SUMMARY echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY # Extract package results grep "^ok\|^FAIL" test-output.log | while read line; do if [[ $line == ok* ]]; then pkg=$(echo $line | awk '{print $2}') echo "| $pkg | โœ… PASS |" >> $GITHUB_STEP_SUMMARY elif [[ $line == FAIL* ]]; then pkg=$(echo $line | awk '{print $2}') echo "| $pkg | โŒ FAIL |" >> $GITHUB_STEP_SUMMARY fi done echo "" >> $GITHUB_STEP_SUMMARY # Add detailed results if tests failed if [ $TEST_STATUS -ne 0 ]; then echo "### โŒ Failed Tests Details" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY grep -A 10 "--- FAIL:" test-output.log | head -100 >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi # Set outputs for other steps echo "test-status=$TEST_STATUS" >> $GITHUB_OUTPUT echo "total-tests=$TOTAL_TESTS" >> $GITHUB_OUTPUT echo "passed-tests=$PASSED_TESTS" >> $GITHUB_OUTPUT echo "failed-tests=$FAILED_TESTS" >> $GITHUB_OUTPUT # Exit with the original test status exit $TEST_STATUS - name: Generate coverage report if: always() run: | if [ -f coverage.out ]; then go tool cover -html=coverage.out -o coverage.html COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}') echo "## ๐Ÿ“Š Code Coverage (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Total Coverage: $COVERAGE**" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Add coverage by package echo "### ๐Ÿ“‹ Coverage by Package" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Package | Coverage |" >> $GITHUB_STEP_SUMMARY echo "|---------|----------|" >> $GITHUB_STEP_SUMMARY go tool cover -func=coverage.out | grep -v total | while read line; do if [[ $line == *".go:"* ]]; then pkg=$(echo $line | awk '{print $1}' | cut -d'/' -f1-3) coverage=$(echo $line | awk '{print $3}') echo "| $pkg | $coverage |" >> $GITHUB_STEP_SUMMARY fi done | sort -u echo "" >> $GITHUB_STEP_SUMMARY else echo "## โš ๏ธ Coverage Report" >> $GITHUB_STEP_SUMMARY echo "No coverage file generated" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi - name: Upload test artifacts if: failure() uses: actions/upload-artifact@v4 with: name: test-results-go-${{ matrix.go }} path: | test-output.log coverage.out coverage.html retention-days: 7 - name: Run go vet run: | echo "## ๐Ÿ” Static Analysis (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY VET_OUTPUT=$(go vet ./... 2>&1 || echo "") VET_STATUS=$? if [ $VET_STATUS -eq 0 ]; then echo "โœ… **go vet:** No issues found" >> $GITHUB_STEP_SUMMARY else echo "โŒ **go vet:** Issues found" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "$VET_OUTPUT" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY fi echo "" >> $GITHUB_STEP_SUMMARY exit $VET_STATUS - name: Run go fmt run: | FMT_OUTPUT=$(gofmt -s -l . 2>&1 || echo "") if [ -z "$FMT_OUTPUT" ]; then echo "โœ… **go fmt:** All files properly formatted" >> $GITHUB_STEP_SUMMARY else echo "โŒ **go fmt:** Files need formatting" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "$FMT_OUTPUT" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY exit 1 fi - name: Job Summary if: always() run: | echo "## ๐Ÿ“‹ Job Summary (Go ${{ matrix.go }})" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Step | Status |" >> $GITHUB_STEP_SUMMARY echo "|------|--------|" >> $GITHUB_STEP_SUMMARY echo "| Dependencies | โœ… Success |" >> $GITHUB_STEP_SUMMARY echo "| Build | โœ… Success |" >> $GITHUB_STEP_SUMMARY echo "| Tests | ${{ steps.test.outcome == 'success' && 'โœ… Success' || 'โŒ Failed' }} |" >> $GITHUB_STEP_SUMMARY echo "| Coverage | ${{ job.status == 'success' && 'โœ… Generated' || 'โš ๏ธ Partial' }} |" >> $GITHUB_STEP_SUMMARY echo "| Static Analysis | ${{ job.status == 'success' && 'โœ… Clean' || 'โŒ Issues' }} |" >> $GITHUB_STEP_SUMMARY echo "| Code Formatting | ${{ job.status == 'success' && 'โœ… Clean' || 'โŒ Issues' }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 with: flags: Go ${{ matrix.go }} slug: kjanat/articulate-parser token: ${{ secrets.CODECOV_TOKEN }} - name: Upload test results to Codecov if: ${{ !cancelled() }} uses: codecov/test-results-action@v1 with: flags: Go ${{ matrix.go }} token: ${{ secrets.CODECOV_TOKEN }} dependency-review: name: Dependency Review runs-on: ubuntu-latest permissions: contents: read if: github.event_name == 'pull_request' steps: - name: 'Checkout Repository' uses: actions/checkout@v4 - name: 'Dependency Review' uses: actions/dependency-review-action@v4 with: fail-on-severity: moderate comment-summary-in-pr: always release: name: Release runs-on: ubuntu-latest if: github.ref_type == 'tag' permissions: contents: write needs: [ "test" ] steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Set up Go uses: actions/setup-go@v5 with: go-version-file: 'go.mod' check-latest: true - name: Run tests run: | echo "## ๐Ÿš€ Release Tests" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY go test -v ./... 2>&1 | tee release-test-output.log TEST_STATUS=$? TOTAL_TESTS=$(grep -c "=== RUN" release-test-output.log || echo "0") PASSED_TESTS=$(grep -c "--- PASS:" release-test-output.log || echo "0") FAILED_TESTS=$(grep -c "--- FAIL:" release-test-output.log || echo "0") echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Total Tests | $TOTAL_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Passed | โœ… $PASSED_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Failed | โŒ $FAILED_TESTS |" >> $GITHUB_STEP_SUMMARY echo "| Status | $([ $TEST_STATUS -eq 0 ] && echo "โœ… PASSED" || echo "โŒ FAILED") |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY exit $TEST_STATUS - name: Install UPX run: | sudo apt-get update sudo apt-get install -y upx - name: Build binaries run: | echo "## ๐Ÿ”จ Build Process" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Set the build time environment variable BUILD_TIME=$(date -u +'%Y-%m-%dT%H:%M:%SZ') # Add run permissions to the build script chmod +x ./scripts/build.sh # Display help information for the build script ./scripts/build.sh --help echo "**Build Configuration:**" >> $GITHUB_STEP_SUMMARY echo "- Version: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY echo "- Build Time: $BUILD_TIME" >> $GITHUB_STEP_SUMMARY echo "- Git Commit: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Build for all platforms ./scripts/build.sh \ --verbose \ -ldflags "-s -w -X github.com/kjanat/articulate-parser/internal/version.Version=${{ github.ref_name }} -X github.com/kjanat/articulate-parser/internal/version.BuildTime=$BUILD_TIME -X github.com/kjanat/articulate-parser/internal/version.GitCommit=${{ github.sha }}" - name: Compress binaries with UPX run: | echo "## ๐Ÿ“ฆ Binary Compression" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Compressing binaries with UPX..." cd build/ # Get original sizes echo "**Original sizes:**" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY ls -lah >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY # Compress all binaries except Darwin (macOS) binaries as UPX doesn't work well with recent macOS versions for binary in articulate-parser-*; do if [[ "$binary" == *"darwin"* ]]; then echo "Skipping UPX compression for $binary (macOS compatibility)" else echo "Compressing $binary..." upx --best --lzma "$binary" || { echo "Warning: UPX compression failed for $binary, keeping original" } fi done echo "**Final sizes:**" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY ls -lah >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - name: Upload a Build Artifact uses: actions/upload-artifact@v4.6.2 with: name: build-artifacts path: build/ if-no-files-found: ignore retention-days: 1 compression-level: 9 overwrite: true include-hidden-files: true - name: Create Release uses: softprops/action-gh-release@v2 with: files: build/* generate_release_notes: true draft: false prerelease: ${{ startsWith(github.ref, 'refs/tags/v0.') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}