diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d0564a0..d6952ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,35 +2,230 @@ name: Build Check on: [pull_request, push] permissions: contents: read + pull-requests: write # Required to post comments on PRs jobs: - build-windows: - runs-on: windows-latest + # Matrix job that compiles and tests all architectures + build-and-test: + strategy: + fail-fast: false # Continue testing other architectures even if one fails + matrix: + include: + # x64 architecture - native runner + - arch: x64 + runner: windows-latest + vcvars_arch: x64 + # x86 architecture - runs on x64 via WoW64 + - arch: x86 + runner: windows-latest + vcvars_arch: x64_x86 + # ARM64 architecture - native ARM runner for testing + - arch: arm64 + runner: windows-11-arm + vcvars_arch: arm64 + + runs-on: ${{ matrix.runner }} + steps: - uses: actions/checkout@v4 - - name: Setup MSVC + - name: Setup MSVC for ${{ matrix.arch }} uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.vcvars_arch }} - - name: Compile + - name: Compile for ${{ matrix.arch }} shell: pwsh run: | - cl /O2 /std:c++20 /EHsc main.cpp /DUNICODE /D_UNICODE /Fe:win-witr.exe - # Add the current directory (where win-witr.exe was compiled) to PATH - $env:PATH = "$PWD;$env:PATH" - - # Verify the exe is accessible - Write-Host "Checking win-witr.exe availability..." - win-witr --version - - name: Run Tests + # Compile the executable with architecture-specific name + cl /O2 /std:c++20 /EHsc main.cpp /DUNICODE /D_UNICODE /Fe:win-witr-${{ matrix.arch }}.exe + + # Create a copy with the standard name for tests + Copy-Item -Path "win-witr-${{ matrix.arch }}.exe" -Destination "win-witr.exe" + + # Add the current directory to PATH + $env:PATH = "$PWD;$env:PATH" + + # Verify the exe is accessible + Write-Host "Checking win-witr-${{ matrix.arch }}.exe availability..." + .\win-witr-${{ matrix.arch }}.exe --version + + - name: Run Tests for ${{ matrix.arch }} + id: run_tests shell: pwsh run: | + # Initialize test counters + $totalTests = 0 + $passedTests = 0 + $failedTests = 0 + $testResults = @() + + # Add the current directory to PATH + $env:PATH = "$PWD;$env:PATH" + # Run all test .bat files Get-ChildItem -Path tests -Recurse -Filter *.bat | ForEach-Object { - Write-Host "Running test: $($_.FullName)" - & $_.FullName - if ($LASTEXITCODE -ne 0) { - Write-Error "Test failed: $($_.Name)" - exit 1 + $totalTests++ + $testName = $_.Name + Write-Host "Running test: $testName" + + # Initialize output variable outside try block + $output = $null + + try { + # Run the test and capture output and exit code + $output = & $_.FullName 2>&1 + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0) { + $passedTests++ + # Include output in the result + $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" } + $testResults += "✅ $testName - PASSED$outputText" + Write-Host "✅ Test passed: $testName" + } else { + $failedTests++ + # Include output and exit code in the result + $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" } + $testResults += "❌ $testName - FAILED (Exit code: $exitCode)$outputText" + Write-Host "❌ Test failed: $testName (Exit code: $exitCode)" + } + } catch { + $failedTests++ + # Include exception and any captured output + $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" } + $testResults += "❌ $testName - FAILED (Exception: $_)$outputText" + Write-Host "❌ Test failed with exception: $testName" } } - + + # Output test summary + Write-Host "`n=== Test Summary for ${{ matrix.arch }} ===" + Write-Host "Total: $totalTests" + Write-Host "Passed: $passedTests" + Write-Host "Failed: $failedTests" + + # Store results for PR comment + $results = @{ + total = $totalTests + passed = $passedTests + failed = $failedTests + details = $testResults -join "`n" + } + + # Export results to GitHub output using multiline format + "total=$totalTests" >> $env:GITHUB_OUTPUT + "passed=$passedTests" >> $env:GITHUB_OUTPUT + "failed=$failedTests" >> $env:GITHUB_OUTPUT + $delimiter = "EOF_DETAILS_$(Get-Date -Format 'yyyyMMddHHmmss')" + "details<<$delimiter" >> $env:GITHUB_OUTPUT + $testResults -join "`n" >> $env:GITHUB_OUTPUT + "$delimiter" >> $env:GITHUB_OUTPUT + + # Exit with error if any tests failed + if ($failedTests -gt 0) { + Write-Error "Some tests failed for ${{ matrix.arch }}" + exit 1 + } + + # Upload test results as artifacts for the comment job + - name: Save test results + if: always() + shell: pwsh + run: | + # Determine job status based on previous steps + $jobStatus = if ("${{ steps.run_tests.outcome }}" -eq "success") { "success" } else { "failure" } + + $results = @{ + arch = "${{ matrix.arch }}" + status = $jobStatus + total = "${{ steps.run_tests.outputs.total }}" + passed = "${{ steps.run_tests.outputs.passed }}" + failed = "${{ steps.run_tests.outputs.failed }}" + details = "${{ steps.run_tests.outputs.details }}" + } + + $results | ConvertTo-Json | Out-File -FilePath "test-results-${{ matrix.arch }}.json" + + - name: Upload test results artifact + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ matrix.arch }} + path: test-results-${{ matrix.arch }}.json + + # Job to post test results as a PR comment + post-test-results: + needs: build-and-test + if: always() && github.event_name == 'pull_request' + runs-on: ubuntu-latest + permissions: + pull-requests: write + + steps: + - name: Download all test results + uses: actions/download-artifact@v4 + with: + pattern: test-results-* + merge-multiple: true + + - name: Generate and post comment + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + + // Read all test result files + const files = fs.readdirSync('.').filter(f => f.startsWith('test-results-') && f.endsWith('.json')); + + let commentBody = '## 🧪 Test Results\n\n'; + let allPassed = true; + + // Process each architecture + for (const file of files) { + const data = JSON.parse(fs.readFileSync(file, 'utf8')); + const arch = data.arch; + const status = data.status || 'unknown'; + const total = data.total || 0; + const passed = data.passed || 0; + const failed = data.failed || 0; + + // Mark as failed if either tests failed OR job status is not success + if (failed > 0 || status !== 'success') { + allPassed = false; + } + + // Determine emoji based on both test results and job status + const emoji = (failed === 0 && status === 'success') ? '✅' : '❌'; + commentBody += `### ${emoji} ${arch.toUpperCase()}\n`; + + // Show appropriate message based on job status + if (status !== 'success') { + commentBody += `**Job failed** - Tests may not have run due to compile or setup failure\n\n`; + } else { + commentBody += `**${passed}/${total} tests passed**\n\n`; + } + + if (data.details && data.details.trim()) { + commentBody += '
\n'; + commentBody += 'Test Details\n\n'; + commentBody += '```\n'; + commentBody += data.details; + commentBody += '\n```\n'; + commentBody += '
\n\n'; + } + } + + if (allPassed) { + commentBody += '\n✨ All tests passed across all architectures!\n'; + } else { + commentBody += '\n⚠️ Some tests failed. Please review the details above.\n'; + } + + // Post comment to PR + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: commentBody + }); + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7958ac8..9b84260 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,6 +13,8 @@ permissions: jobs: prepare: name: Prepare release (check files, version, notes) + # Only run if PR was actually merged + if: github.event.pull_request.merged == true runs-on: ubuntu-latest outputs: should_release: ${{ steps.check_files.outputs.should_release }} @@ -155,6 +157,14 @@ jobs: Write-Output "DEBUG: Base SHA: $baseSha" Write-Output "DEBUG: Head SHA: $headSha" + # Get the merge commit message using the actual merge commit SHA + # The merge_commit_sha is the SHA of the commit created when the PR is merged + $mergeCommitSha = "${{ github.event.pull_request.merge_commit_sha }}" + Write-Output "DEBUG: Merge commit SHA: $mergeCommitSha" + + $mergeCommitBody = git log -1 --pretty=format:"%b" $mergeCommitSha + Write-Output "DEBUG: Merge commit body: $mergeCommitBody" + # Get all commit messages in the PR $commits = @(git log --pretty=format:"%h|%s|%b" "$baseSha..$headSha") Write-Output "DEBUG: Found $($commits.Count) commits in PR" @@ -214,8 +224,17 @@ jobs: } } - # Build release notes - $releaseNotes = "## Changes`n`n" + # Build release notes with merge commit extended description at the top + $releaseNotes = "" + + # Add merge commit extended description if it exists + if (-not [string]::IsNullOrWhiteSpace($mergeCommitBody)) { + $releaseNotes += "## Release Notes`n`n" + $releaseNotes += "$mergeCommitBody`n`n" + $releaseNotes += "---`n`n" + } + + $releaseNotes += "## Changes`n`n" if ($features.Count -gt 0) { $releaseNotes += "### ✨ Features`n"