@@ -2,36 +2,231 @@ name: Build Check
22on : [pull_request, push]
33permissions :
44 contents : read
5+ pull-requests : write # Required to post comments on PRs
56jobs :
6- build-windows :
7- runs-on : windows-latest
7+ # Matrix job that compiles and tests all architectures
8+ build-and-test :
9+ strategy :
10+ fail-fast : false # Continue testing other architectures even if one fails
11+ matrix :
12+ include :
13+ # x64 architecture - native runner
14+ - arch : x64
15+ runner : windows-latest
16+ vcvars_arch : x64
17+ # x86 architecture - runs on x64 via WoW64
18+ - arch : x86
19+ runner : windows-latest
20+ vcvars_arch : x64_x86
21+ # ARM64 architecture - native ARM runner for testing
22+ - arch : arm64
23+ runner : windows-11-arm
24+ vcvars_arch : arm64
25+
26+ runs-on : ${{ matrix.runner }}
27+
828 steps :
929 - uses : actions/checkout@v4
1030
11- - name : Setup MSVC
31+ - name : Setup MSVC for ${{ matrix.arch }}
1232 uses : ilammy/msvc-dev-cmd@v1
33+ with :
34+ arch : ${{ matrix.vcvars_arch }}
1335
14- - name : Compile
36+ - name : Compile for ${{ matrix.arch }}
1537 shell : pwsh
1638 run : |
17- cl /O2 /std:c++20 /EHsc main.cpp /DUNICODE /D_UNICODE /Fe:win-witr.exe
18- # Add the current directory (where win-witr.exe was compiled) to PATH
19- $env:PATH = "$PWD;$env:PATH"
20-
21- # Verify the exe is accessible
22- Write-Host "Checking win-witr.exe availability..."
23- win-witr --version
24- - name : Run Tests
39+ # Compile the executable with architecture-specific name
40+ cl /O2 /std:c++20 /EHsc main.cpp /DUNICODE /D_UNICODE /Fe:win-witr-${{ matrix.arch }}.exe
41+
42+ # Create a copy with the standard name for tests
43+ Copy-Item -Path "win-witr-${{ matrix.arch }}.exe" -Destination "win-witr.exe"
44+
45+ # Add the current directory to PATH
46+ $env:PATH = "$PWD;$env:PATH"
47+
48+ # Verify the exe is accessible
49+ Write-Host "Checking win-witr-${{ matrix.arch }}.exe availability..."
50+ .\win-witr-${{ matrix.arch }}.exe --version
51+
52+ - name : Run Tests for ${{ matrix.arch }}
53+ id : run_tests
2554 shell : pwsh
2655 run : |
56+ # Initialize test counters
57+ $totalTests = 0
58+ $passedTests = 0
59+ $failedTests = 0
60+ $testResults = @()
61+
62+ # Add the current directory to PATH
63+ $env:PATH = "$PWD;$env:PATH"
64+
2765 # Run all test .bat files
2866 $env:force_ansi = 1
2967 Get-ChildItem -Path tests -Recurse -Filter *.bat | ForEach-Object {
30- Write-Host "Running test: $($_.FullName)"
31- & $_.FullName
32- if ($LASTEXITCODE -ne 0) {
33- Write-Error "Test failed: $($_.Name)"
34- exit 1
68+ $totalTests++
69+ $testName = $_.Name
70+ Write-Host "Running test: $testName"
71+
72+ # Initialize output variable outside try block
73+ $output = $null
74+
75+ try {
76+ # Run the test and capture output and exit code
77+ $output = & $_.FullName 2>&1
78+ $exitCode = $LASTEXITCODE
79+
80+ if ($exitCode -eq 0) {
81+ $passedTests++
82+ # Include output in the result
83+ $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" }
84+ $testResults += "✅ $testName - PASSED$outputText"
85+ Write-Host "✅ Test passed: $testName"
86+ } else {
87+ $failedTests++
88+ # Include output and exit code in the result
89+ $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" }
90+ $testResults += "❌ $testName - FAILED (Exit code: $exitCode)$outputText"
91+ Write-Host "❌ Test failed: $testName (Exit code: $exitCode)"
92+ }
93+ } catch {
94+ $failedTests++
95+ # Include exception and any captured output
96+ $outputText = if ($output) { "`n Output: $($output -join "`n ")" } else { "" }
97+ $testResults += "❌ $testName - FAILED (Exception: $_)$outputText"
98+ Write-Host "❌ Test failed with exception: $testName"
3599 }
36100 }
37-
101+
102+ # Output test summary
103+ Write-Host "`n=== Test Summary for ${{ matrix.arch }} ==="
104+ Write-Host "Total: $totalTests"
105+ Write-Host "Passed: $passedTests"
106+ Write-Host "Failed: $failedTests"
107+
108+ # Store results for PR comment
109+ $results = @{
110+ total = $totalTests
111+ passed = $passedTests
112+ failed = $failedTests
113+ details = $testResults -join "`n"
114+ }
115+
116+ # Export results to GitHub output using multiline format
117+ "total=$totalTests" >> $env:GITHUB_OUTPUT
118+ "passed=$passedTests" >> $env:GITHUB_OUTPUT
119+ "failed=$failedTests" >> $env:GITHUB_OUTPUT
120+ $delimiter = "EOF_DETAILS_$(Get-Date -Format 'yyyyMMddHHmmss')"
121+ "details<<$delimiter" >> $env:GITHUB_OUTPUT
122+ $testResults -join "`n" >> $env:GITHUB_OUTPUT
123+ "$delimiter" >> $env:GITHUB_OUTPUT
124+
125+ # Exit with error if any tests failed
126+ if ($failedTests -gt 0) {
127+ Write-Error "Some tests failed for ${{ matrix.arch }}"
128+ exit 1
129+ }
130+
131+ # Upload test results as artifacts for the comment job
132+ - name : Save test results
133+ if : always()
134+ shell : pwsh
135+ run : |
136+ # Determine job status based on previous steps
137+ $jobStatus = if ("${{ steps.run_tests.outcome }}" -eq "success") { "success" } else { "failure" }
138+
139+ $results = @{
140+ arch = "${{ matrix.arch }}"
141+ status = $jobStatus
142+ total = "${{ steps.run_tests.outputs.total }}"
143+ passed = "${{ steps.run_tests.outputs.passed }}"
144+ failed = "${{ steps.run_tests.outputs.failed }}"
145+ details = "${{ steps.run_tests.outputs.details }}"
146+ }
147+
148+ $results | ConvertTo-Json | Out-File -FilePath "test-results-${{ matrix.arch }}.json"
149+
150+ - name : Upload test results artifact
151+ if : always()
152+ uses : actions/upload-artifact@v4
153+ with :
154+ name : test-results-${{ matrix.arch }}
155+ path : test-results-${{ matrix.arch }}.json
156+
157+ # Job to post test results as a PR comment
158+ post-test-results :
159+ needs : build-and-test
160+ if : always() && github.event_name == 'pull_request'
161+ runs-on : ubuntu-latest
162+ permissions :
163+ pull-requests : write
164+
165+ steps :
166+ - name : Download all test results
167+ uses : actions/download-artifact@v4
168+ with :
169+ pattern : test-results-*
170+ merge-multiple : true
171+
172+ - name : Generate and post comment
173+ uses : actions/github-script@v7
174+ with :
175+ script : |
176+ const fs = require('fs');
177+
178+ // Read all test result files
179+ const files = fs.readdirSync('.').filter(f => f.startsWith('test-results-') && f.endsWith('.json'));
180+
181+ let commentBody = '## 🧪 Test Results\n\n';
182+ let allPassed = true;
183+
184+ // Process each architecture
185+ for (const file of files) {
186+ const data = JSON.parse(fs.readFileSync(file, 'utf8'));
187+ const arch = data.arch;
188+ const status = data.status || 'unknown';
189+ const total = data.total || 0;
190+ const passed = data.passed || 0;
191+ const failed = data.failed || 0;
192+
193+ // Mark as failed if either tests failed OR job status is not success
194+ if (failed > 0 || status !== 'success') {
195+ allPassed = false;
196+ }
197+
198+ // Determine emoji based on both test results and job status
199+ const emoji = (failed === 0 && status === 'success') ? '✅' : '❌';
200+ commentBody += `### ${emoji} ${arch.toUpperCase()}\n`;
201+
202+ // Show appropriate message based on job status
203+ if (status !== 'success') {
204+ commentBody += `**Job failed** - Tests may not have run due to compile or setup failure\n\n`;
205+ } else {
206+ commentBody += `**${passed}/${total} tests passed**\n\n`;
207+ }
208+
209+ if (data.details && data.details.trim()) {
210+ commentBody += '<details>\n';
211+ commentBody += '<summary>Test Details</summary>\n\n';
212+ commentBody += '```\n';
213+ commentBody += data.details;
214+ commentBody += '\n```\n';
215+ commentBody += '</details>\n\n';
216+ }
217+ }
218+
219+ if (allPassed) {
220+ commentBody += '\n✨ All tests passed across all architectures!\n';
221+ } else {
222+ commentBody += '\n⚠️ Some tests failed. Please review the details above.\n';
223+ }
224+
225+ // Post comment to PR
226+ await github.rest.issues.createComment({
227+ owner: context.repo.owner,
228+ repo: context.repo.repo,
229+ issue_number: context.issue.number,
230+ body: commentBody
231+ });
232+
0 commit comments