From 6dd381689fe420fb22a02d27b3903d21d320653a Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Thu, 8 Jan 2026 18:16:58 +0530 Subject: [PATCH 1/7] feat: add GitHub Actions workflow for building and testing Merod on Windows --- .../workflows/merobox-workflows-windows.yml | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 .github/workflows/merobox-workflows-windows.yml diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml new file mode 100644 index 000000000..42afb58b6 --- /dev/null +++ b/.github/workflows/merobox-workflows-windows.yml @@ -0,0 +1,122 @@ +name: Merobox Windows Test + +permissions: + contents: read + +on: + push: + branches: [master] + paths: + - "crates/**" + - ".github/workflows/merobox-workflows-windows.yml" + + pull_request: + branches: [master] + paths: + - "crates/**" + - ".github/workflows/merobox-workflows-windows.yml" + + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + CARGO_TERM_COLOR: always + RUST_BACKTRACE: 1 + +jobs: + build-merod: + name: Build Merod Binary + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + - name: Cache Rust dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Build merod binary + run: cargo build --release -p merod + shell: pwsh + + - name: Verify binary exists + run: | + if (-not (Test-Path "target/release/merod.exe")) { + exit 1 + } + shell: pwsh + + - name: Upload merod binary artifact + uses: actions/upload-artifact@v4 + with: + name: merod-windows-binary + path: target/release/merod.exe + retention-days: 1 + + test: + name: Test Nodes on Windows + needs: build-merod + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download merod binary artifact + uses: actions/download-artifact@v4 + with: + name: merod-windows-binary + path: target/release/ + + - name: Verify merod binary + run: | + if (-not (Test-Path "target/release/merod.exe")) { + exit 1 + } + shell: pwsh + + - name: Set up Python 3.11 + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Clone merobox + run: | + git clone https://github.com/calimero-network/merobox.git + shell: pwsh + + - name: Install merobox + run: | + pip install -e ./merobox + shell: pwsh + + - name: Verify merobox installation + run: | + merobox --version + shell: pwsh + + - name: Get merod binary path + id: merod-path + run: | + $binaryPath = (Resolve-Path "target/release/merod.exe").Path + echo "path=$binaryPath" >> $env:GITHUB_OUTPUT + shell: pwsh + + - name: Run nodes test + run: | + merobox run --count 2 --no-docker --binary-path "${{ steps.merod-path.outputs.path }}" + shell: pwsh From b7a89e9cb2454247faec34a23d315da0be122816 Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Thu, 8 Jan 2026 18:59:37 +0530 Subject: [PATCH 2/7] feat: set UTF-8 encoding for Windows workflow to ensure proper character handling --- .github/workflows/merobox-workflows-windows.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index 42afb58b6..ab1c33ac2 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -72,6 +72,8 @@ jobs: name: Test Nodes on Windows needs: build-merod runs-on: windows-latest + env: + PYTHONIOENCODING: utf-8 steps: - name: Checkout code uses: actions/checkout@v4 @@ -116,7 +118,16 @@ jobs: echo "path=$binaryPath" >> $env:GITHUB_OUTPUT shell: pwsh + - name: Set UTF-8 encoding + run: | + $env:PYTHONIOENCODING = "utf-8" + [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + chcp 65001 | Out-Null + shell: pwsh + - name: Run nodes test + env: + PYTHONIOENCODING: utf-8 run: | merobox run --count 2 --no-docker --binary-path "${{ steps.merod-path.outputs.path }}" shell: pwsh From 5afb2c63345e960ceaeb72974cf3d6415a226c1c Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Thu, 8 Jan 2026 19:24:31 +0530 Subject: [PATCH 3/7] feat: enhance Windows workflow with error handling and node status check for merobox run --- .github/workflows/merobox-workflows-windows.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index ab1c33ac2..4e08e6222 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -130,4 +130,12 @@ jobs: PYTHONIOENCODING: utf-8 run: | merobox run --count 2 --no-docker --binary-path "${{ steps.merod-path.outputs.path }}" + if ($LASTEXITCODE -ne 0) { + Write-Host "merobox run exited with code $LASTEXITCODE" + Write-Host "Checking node status..." + merobox list + exit $LASTEXITCODE + } + Write-Host "All nodes started successfully" + merobox list shell: pwsh From 72356b5d24e5e7d15a29817e3f8d4bfa8c7920f1 Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Fri, 9 Jan 2026 16:22:46 +0530 Subject: [PATCH 4/7] feat: expand Windows workflow to include app builds, artifact caching, and failure reporting --- .../workflows/merobox-workflows-windows.yml | 204 ++++++++++++++++-- 1 file changed, 185 insertions(+), 19 deletions(-) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index 4e08e6222..a243504fd 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -1,4 +1,4 @@ -name: Merobox Windows Test +name: Merobox Workflows - Windows permissions: contents: read @@ -8,12 +8,14 @@ on: branches: [master] paths: - "crates/**" + - "apps/**" - ".github/workflows/merobox-workflows-windows.yml" pull_request: branches: [master] paths: - "crates/**" + - "apps/**" - ".github/workflows/merobox-workflows-windows.yml" workflow_dispatch: @@ -27,6 +29,49 @@ env: RUST_BACKTRACE: 1 jobs: + build-apps: + name: Build Apps + runs-on: windows-latest + outputs: + cache-key: ${{ steps.cache-key.outputs.key }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + - name: Cache Rust dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Generate cache key + id: cache-key + run: echo "key=${{ runner.os }}-build-${{ github.sha }}" >> $env:GITHUB_OUTPUT + shell: pwsh + + - name: Build all apps + run: bash scripts/build-all-apps.sh + shell: pwsh + + - name: Cache build artifacts + uses: actions/cache@v4 + with: + path: | + target/app-release + apps/*/res/*.wasm + apps/*/res/*.mpk + key: ${{ steps.cache-key.outputs.key }} + build-merod: name: Build Merod Binary runs-on: windows-latest @@ -69,8 +114,8 @@ jobs: retention-days: 1 test: - name: Test Nodes on Windows - needs: build-merod + name: Run All Merobox Workflows (Windows) + needs: [build-apps, build-merod] runs-on: windows-latest env: PYTHONIOENCODING: utf-8 @@ -78,6 +123,15 @@ jobs: - name: Checkout code uses: actions/checkout@v4 + - name: Restore build artifacts + uses: actions/cache@v4 + with: + path: | + target/app-release + apps/*/res/*.wasm + apps/*/res/*.mpk + key: ${{ needs.build-apps.outputs.cache-key }} + - name: Download merod binary artifact uses: actions/download-artifact@v4 with: @@ -111,13 +165,6 @@ jobs: merobox --version shell: pwsh - - name: Get merod binary path - id: merod-path - run: | - $binaryPath = (Resolve-Path "target/release/merod.exe").Path - echo "path=$binaryPath" >> $env:GITHUB_OUTPUT - shell: pwsh - - name: Set UTF-8 encoding run: | $env:PYTHONIOENCODING = "utf-8" @@ -125,17 +172,136 @@ jobs: chcp 65001 | Out-Null shell: pwsh - - name: Run nodes test + - name: Get merod binary path + id: merod-path + run: | + $binaryPath = (Resolve-Path "target/release/merod.exe").Path + echo "path=$binaryPath" >> $env:GITHUB_OUTPUT + shell: pwsh + + - name: Run All Workflows + id: run_workflows env: PYTHONIOENCODING: utf-8 run: | - merobox run --count 2 --no-docker --binary-path "${{ steps.merod-path.outputs.path }}" - if ($LASTEXITCODE -ne 0) { - Write-Host "merobox run exited with code $LASTEXITCODE" - Write-Host "Checking node status..." - merobox list - exit $LASTEXITCODE + $failedWorkflows = @() + $workflowFiles = Get-ChildItem -Path "apps\*" -Include "*.yml", "*.yaml" -Recurse | Where-Object { $_.DirectoryName -like "*workflows*" } + + foreach ($workflowFile in $workflowFiles) { + $appDir = $workflowFile.Directory.Parent.FullName + $workflowFileName = $workflowFile.Name + $maxAttempts = 2 + $attempt = 1 + $success = $false + + while ($attempt -le $maxAttempts) { + if ($attempt -gt 1) { + merobox stop --all 2>$null + merobox nuke --force 2>$null + Start-Sleep -Seconds 2 + } + + Push-Location $appDir + try { + $workflowPath = "workflows\$workflowFileName" + $binaryPath = "${{ steps.merod-path.outputs.path }}" + + merobox bootstrap run ` + $workflowPath ` + --no-docker ` + --binary-path $binaryPath ` + --e2e-mode + + if ($LASTEXITCODE -eq 0) { + $success = $true + break + } + } finally { + Pop-Location + } + + $attempt++ + } + + merobox stop --all 2>$null + merobox nuke --force 2>$null + + if (-not $success) { + $failedWorkflows += $workflowFile.FullName + } + + Start-Sleep -Seconds 2 + } + + if ($failedWorkflows.Count -gt 0) { + echo "has_failures=true" >> $env:GITHUB_OUTPUT + $failedWorkflows | Out-File -FilePath "apps\failed_workflows.txt" -Encoding utf8 + } else { + echo "has_failures=false" >> $env:GITHUB_OUTPUT } - Write-Host "All nodes started successfully" - merobox list shell: pwsh + + - name: Upload Failed Workflows + if: steps.run_workflows.outputs.has_failures == 'true' + uses: actions/upload-artifact@v4 + with: + name: failed-workflows-windows + path: apps/failed_workflows.txt + retention-days: 1 + + - name: Fail if workflows failed + if: steps.run_workflows.outputs.has_failures == 'true' + run: exit 1 + shell: pwsh + + - name: Upload Workflow Data Artifacts + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: merobox-workflow-data-windows-${{ github.sha }} + path: | + apps/*/res/*.wasm + apps/*/res/abi.json + apps/*/res/*.mpk + apps/*/res/state-schema.json + apps/*/data/ + retention-days: 7 + if-no-files-found: warn + + comment: + name: Report Failed Workflows + needs: test + runs-on: ubuntu-latest + if: always() && github.event_name == 'pull_request' + steps: + - name: Download Failed Workflows + id: download + uses: actions/download-artifact@v4 + continue-on-error: true + with: + name: failed-workflows-windows + + - name: Prepare Failure Comment + if: steps.download.outcome == 'success' + run: | + failed_list=$(cat failed_workflows.txt | sed 's/^/- /') + message="## Merobox Workflows Failed (Windows) + + The following workflow(s) failed after retries: + $failed_list + + Please check the workflow logs for more details." + + jq -n \ + --arg pr '${{ github.event.number }}' \ + --arg tag merobox-workflows-windows-report \ + --arg mode recreate \ + --arg message "$message" \ + '{pr: $pr, tag: $tag, mode: $mode, message: $message}' > payload.json + + - name: Upload Comment + if: steps.download.outcome == 'success' + uses: actions/upload-artifact@v4 + with: + name: pr-comment-payload-windows + path: payload.json From c57d0b77883e3f796ba05bb1b02d2b2f4f922215 Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Fri, 9 Jan 2026 16:33:10 +0530 Subject: [PATCH 5/7] refactor: remove redundant UTF-8 encoding setup from Windows workflow and consolidate it into the merod binary path step --- .github/workflows/merobox-workflows-windows.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index a243504fd..0ff606364 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -165,13 +165,6 @@ jobs: merobox --version shell: pwsh - - name: Set UTF-8 encoding - run: | - $env:PYTHONIOENCODING = "utf-8" - [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 - chcp 65001 | Out-Null - shell: pwsh - - name: Get merod binary path id: merod-path run: | @@ -184,6 +177,9 @@ jobs: env: PYTHONIOENCODING: utf-8 run: | + [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 + chcp 65001 | Out-Null + $failedWorkflows = @() $workflowFiles = Get-ChildItem -Path "apps\*" -Include "*.yml", "*.yaml" -Recurse | Where-Object { $_.DirectoryName -like "*workflows*" } From 219264a15bffd6db5931c499d6af39c42c65d305 Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Fri, 9 Jan 2026 16:37:56 +0530 Subject: [PATCH 6/7] fix: update Windows workflow to correctly execute build script and refine workflow file retrieval logic --- .github/workflows/merobox-workflows-windows.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index 0ff606364..0ac9b2e16 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -60,8 +60,8 @@ jobs: shell: pwsh - name: Build all apps - run: bash scripts/build-all-apps.sh - shell: pwsh + run: ./scripts/build-all-apps.sh + shell: bash - name: Cache build artifacts uses: actions/cache@v4 @@ -181,7 +181,10 @@ jobs: chcp 65001 | Out-Null $failedWorkflows = @() - $workflowFiles = Get-ChildItem -Path "apps\*" -Include "*.yml", "*.yaml" -Recurse | Where-Object { $_.DirectoryName -like "*workflows*" } + $workflowFiles = Get-ChildItem -Path "apps" -Recurse -Include "*.yml", "*.yaml" | Where-Object { + $_.Directory.Name -eq "workflows" -and + $_.FullName -match "\\workflows\\[^\\]+\.(yml|yaml)$" + } foreach ($workflowFile in $workflowFiles) { $appDir = $workflowFile.Directory.Parent.FullName From 80f6afc20e38bcac74f7b2cbb18678ca18e58366 Mon Sep 17 00:00:00 2001 From: rtb-12 Date: Fri, 9 Jan 2026 18:13:06 +0530 Subject: [PATCH 7/7] feat: enhance Windows workflow with DLL dependency checks and binary execution tests --- .../workflows/merobox-workflows-windows.yml | 152 ++++++++++++++++-- 1 file changed, 141 insertions(+), 11 deletions(-) diff --git a/.github/workflows/merobox-workflows-windows.yml b/.github/workflows/merobox-workflows-windows.yml index 0ac9b2e16..4886693c3 100644 --- a/.github/workflows/merobox-workflows-windows.yml +++ b/.github/workflows/merobox-workflows-windows.yml @@ -145,6 +145,32 @@ jobs: } shell: pwsh + - name: Check DLL dependencies + run: | + $binaryPath = "target/release/merod.exe" + Write-Host "Checking DLL dependencies for $binaryPath" + + # Use dumpbin if available (part of Visual Studio tools) + $dumpbin = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + if (Test-Path $dumpbin) { + Write-Host "Visual Studio tools found" + } + + # Alternative: Use PowerShell to check for common DLL issues + Write-Host "Checking for Visual C++ Runtime..." + $vcRedist = Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object { $_.DisplayName -like "*Visual C++*" } | Select-Object -First 5 + if ($vcRedist) { + Write-Host "Found Visual C++ Runtime installations:" + $vcRedist | ForEach-Object { Write-Host " - $($_.DisplayName)" } + } else { + Write-Host "Warning: No Visual C++ Runtime found in registry" + } + + # Check if RocksDB DLL might be needed + Write-Host "`nNote: If merod uses RocksDB, ensure all required DLLs are available" + shell: pwsh + continue-on-error: true + - name: Set up Python 3.11 uses: actions/setup-python@v5 with: @@ -172,6 +198,27 @@ jobs: echo "path=$binaryPath" >> $env:GITHUB_OUTPUT shell: pwsh + - name: Test merod binary execution + run: | + $binaryPath = "${{ steps.merod-path.outputs.path }}" + Write-Host "Testing merod binary: $binaryPath" + + # Try to run merod --help to verify it can start + $testResult = & $binaryPath --help 2>&1 + $exitCode = $LASTEXITCODE + + if ($exitCode -eq 0 -or $exitCode -eq 1) { + Write-Host "✓ Binary can execute (exit code: $exitCode)" + Write-Host "Output: $($testResult -join "`n")" + } else { + Write-Host "✗ Binary execution test failed with exit code: $exitCode" + Write-Host "Output: $($testResult -join "`n")" + Write-Host "`nThis may indicate missing DLL dependencies." + exit 1 + } + shell: pwsh + continue-on-error: true + - name: Run All Workflows id: run_workflows env: @@ -180,24 +227,27 @@ jobs: [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 chcp 65001 | Out-Null - $failedWorkflows = @() - $workflowFiles = Get-ChildItem -Path "apps" -Recurse -Include "*.yml", "*.yaml" | Where-Object { - $_.Directory.Name -eq "workflows" -and - $_.FullName -match "\\workflows\\[^\\]+\.(yml|yaml)$" - } - - foreach ($workflowFile in $workflowFiles) { + # Set environment to help with DLL loading + $env:PATH = "$env:PATH;$PWD\target\release" + + function Run-Workflow { + param( + [string]$WorkflowFilePath, + [int]$MaxAttempts = 2 + ) + + $workflowFile = Get-Item $WorkflowFilePath $appDir = $workflowFile.Directory.Parent.FullName $workflowFileName = $workflowFile.Name - $maxAttempts = 2 $attempt = 1 $success = $false - while ($attempt -le $maxAttempts) { + while ($attempt -le $MaxAttempts) { if ($attempt -gt 1) { + Write-Host "Retry attempt $attempt for workflow: $WorkflowFilePath" merobox stop --all 2>$null merobox nuke --force 2>$null - Start-Sleep -Seconds 2 + Start-Sleep -Seconds 3 } Push-Location $appDir @@ -205,6 +255,8 @@ jobs: $workflowPath = "workflows\$workflowFileName" $binaryPath = "${{ steps.merod-path.outputs.path }}" + Write-Host "Running workflow: $WorkflowFilePath (attempt $attempt/$MaxAttempts)" + merobox bootstrap run ` $workflowPath ` --no-docker ` @@ -213,7 +265,10 @@ jobs: if ($LASTEXITCODE -eq 0) { $success = $true + Write-Host "✓ Workflow succeeded: $WorkflowFilePath" break + } else { + Write-Host "✗ Workflow failed (attempt $attempt/$MaxAttempts): $WorkflowFilePath" } } finally { Pop-Location @@ -224,19 +279,83 @@ jobs: merobox stop --all 2>$null merobox nuke --force 2>$null + Start-Sleep -Seconds 2 + if (-not $success) { + Write-Host "Workflow failed after $MaxAttempts attempts: $WorkflowFilePath" + Write-Host "Collecting node logs..." + $logFiles = Get-ChildItem -Path "data" -Recurse -Filter "*.log" -ErrorAction SilentlyContinue + foreach ($logFile in $logFiles) { + Write-Host "`n=== Log: $($logFile.FullName) ===" + Get-Content $logFile.FullName -Tail 50 -ErrorAction SilentlyContinue + } + } + + return $success + } + + # First pass: Run all workflows with 1 attempt each (quick pass to identify failures) + Write-Host "=== First Pass: Running All Workflows (1 attempt each) ===" + $failedWorkflows = @() + $workflowFiles = Get-ChildItem -Path "apps" -Recurse -Include "*.yml", "*.yaml" | Where-Object { + $_.Directory.Name -eq "workflows" -and + $_.FullName -match "\\workflows\\[^\\]+\.(yml|yaml)$" + } + + Write-Host "Found $($workflowFiles.Count) workflow(s) to run" + + foreach ($workflowFile in $workflowFiles) { + $success = Run-Workflow -WorkflowFilePath $workflowFile.FullName -MaxAttempts 1 if (-not $success) { $failedWorkflows += $workflowFile.FullName } + } - Start-Sleep -Seconds 2 + Write-Host "`n=== First Pass Complete ===" + Write-Host "Total workflows: $($workflowFiles.Count)" + Write-Host "Successful: $($workflowFiles.Count - $failedWorkflows.Count)" + Write-Host "Failed: $($failedWorkflows.Count)" + + # Second pass: Retry failed workflows with 2 attempts + if ($failedWorkflows.Count -gt 0) { + Write-Host "`n=== Second Pass: Retrying Failed Workflows (2 attempts each) ===" + Write-Host "Retrying $($failedWorkflows.Count) failed workflow(s)" + + # Clean up before retry pass + merobox stop --all 2>$null + merobox nuke --force 2>$null + Start-Sleep -Seconds 5 + + $retryFailedWorkflows = @() + foreach ($failedWorkflow in $failedWorkflows) { + Write-Host "`nRetrying workflow: $failedWorkflow" + $success = Run-Workflow -WorkflowFilePath $failedWorkflow -MaxAttempts 2 + if (-not $success) { + $retryFailedWorkflows += $failedWorkflow + } + } + + Write-Host "`n=== Second Pass Complete ===" + Write-Host "Retried: $($failedWorkflows.Count)" + Write-Host "Still failed: $($retryFailedWorkflows.Count)" + + # Update failed workflows list with final failures + $failedWorkflows = $retryFailedWorkflows } + # Output results if ($failedWorkflows.Count -gt 0) { echo "has_failures=true" >> $env:GITHUB_OUTPUT $failedWorkflows | Out-File -FilePath "apps\failed_workflows.txt" -Encoding utf8 + Write-Host "`n=== Final Results ===" + Write-Host "❌ $($failedWorkflows.Count) workflow(s) failed after retries:" + foreach ($failed in $failedWorkflows) { + Write-Host " - $failed" + } } else { echo "has_failures=false" >> $env:GITHUB_OUTPUT + Write-Host "`n=== Final Results ===" + Write-Host "✓ All workflows passed!" } shell: pwsh @@ -253,6 +372,17 @@ jobs: run: exit 1 shell: pwsh + - name: Upload Node Logs + if: always() + uses: actions/upload-artifact@v4 + with: + name: merobox-node-logs-windows-${{ github.sha }} + path: | + data/**/*.log + apps/*/data/**/*.log + retention-days: 7 + if-no-files-found: warn + - name: Upload Workflow Data Artifacts if: ${{ !cancelled() }} uses: actions/upload-artifact@v4