From 7a9b648006f532442c857b80318af9e2566dcb97 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Mon, 29 Jun 2026 01:46:13 +0000 Subject: [PATCH 1/2] ci: Add GitHub Actions workflow for BasisSyncSimTests - Add .github/workflows/sync-sim-tests.yml with: - EditMode test job (runs on push/PR) - Full matrix runner job (manual/scheduled, exports CSV) - Lint job (csharpier format check) - Add RunAndExportCSV() static method to BasisSyncSimMatrix for CI matrix execution - Supports configurable MatrixOptions via -matrixOptions JSON arg --- .github/workflows/sync-sim-tests.yml | 199 ++++++++++++++++++ .../Editor/SyncTesting/BasisSyncSimMatrix.cs | 57 ++++- 2 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/sync-sim-tests.yml diff --git a/.github/workflows/sync-sim-tests.yml b/.github/workflows/sync-sim-tests.yml new file mode 100644 index 000000000..bcc869161 --- /dev/null +++ b/.github/workflows/sync-sim-tests.yml @@ -0,0 +1,199 @@ +name: Basis Sync Sim Tests + +on: + push: + branches: [main, developer] + paths: + - 'Basis/Packages/com.basis.framework/**' + - '.github/workflows/sync-sim-tests.yml' + pull_request: + branches: [main, developer] + paths: + - 'Basis/Packages/com.basis.framework/**' + - '.github/workflows/sync-sim-tests.yml' + workflow_dispatch: + inputs: + unityVersion: + description: 'Unity version to test (default: 6000.5.1f1)' + required: false + default: '6000.5.1f1' + testFilter: + description: 'NUnit filter (e.g. BasisSyncSimTests.Sim_Converges*)' + required: false + default: 'BasisSyncSimTests' + +env: + UNITY_VERSION: ${{ github.event.inputs.unityVersion || '6000.5.1f1' }} + PROJECT_PATH: Basis + TEST_FILTER: ${{ github.event.inputs.testFilter || 'BasisSyncSimTests' }} + TEST_RESULTS_DIR: ${{ runner.temp }}/test-results + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + +jobs: + test: + name: Unity ${{ env.UNITY_VERSION }} EditMode Tests + runs-on: ubuntu-latest + timeout-minutes: 60 + + steps: + # ─── Checkout ─── + - name: Checkout repository + uses: actions/checkout@v4 + with: + lfs: true + submodules: recursive + + # ─── Cache Unity Editor ─── + - name: Cache Unity Editor + uses: actions/cache@v4 + with: + path: /opt/unity/editors + key: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} + restore-keys: | + unity-editor-${{ env.UNITY_VERSION }}- + unity-editor- + + # ─── Install Unity ─── + - name: Install Unity + uses: game-ci/unity-installer@v4 + with: + unityVersion: ${{ env.UNITY_VERSION }} + cacheKey: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} + + # ─── Cache Library ─── + - name: Cache Library folder + uses: actions/cache@v4 + with: + path: ${{ env.PROJECT_PATH }}/Library + key: library-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}-${{ hashFiles('**/Packages/**', '**/Packages/manifest.json') }} + restore-keys: | + library-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}- + library-${{ env.PROJECT_PATH }}- + + # ─── Activate Unity License ─── + - name: Activate Unity License + if: env.UNITY_LICENSE != '' + uses: game-ci/unity-activate@v3 + with: + license: ${{ env.UNITY_LICENSE }} + unityVersion: ${{ env.UNITY_VERSION }} + + # ─── Run EditMode Tests ─── + - name: Run BasisSyncSimTests (EditMode) + id: test + uses: game-ci/unity-test-runner@v4 + env: + UNITY_LICENSE: ${{ env.UNITY_LICENSE }} + with: + projectPath: ${{ env.PROJECT_PATH }} + unityVersion: ${{ env.UNITY_VERSION }} + testMode: editmode + testPlatform: editmode + filters: ${{ env.TEST_FILTER }} + artifactsPath: ${{ env.TEST_RESULTS_DIR }} + checkTestResults: true + customParameters: -logFile - -batchmode -nographics + + # ─── Upload Test Results ─── + - name: Upload test results (NUnit XML) + if: always() + uses: actions/upload-artifact@v4 + with: + name: test-results-${{ env.UNITY_VERSION }} + path: ${{ env.TEST_RESULTS_DIR }}/*.xml + retention-days: 30 + + # ─── Upload Editor Log (on failure) ─── + - name: Upload Editor.log on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: editor-log-${{ env.UNITY_VERSION }} + path: | + ${{ env.PROJECT_PATH }}/Library/Logs/Unity/Editor.log + ${{ runner.temp }}/unity.log + retention-days: 7 + + # ─── Publish Test Report (PR check) ─── + - name: Publish Test Report + if: github.event_name == 'pull_request' + uses: dorny/test-reporter@v1 + with: + name: Unity EditMode Tests + path: ${{ env.TEST_RESULTS_DIR }}/*.xml + reporter: dotnet-trx + fail-on-error: true + + # ─── Matrix Runner (Full Combinatorial) ─── + matrix-runner: + name: Full Matrix Runner (CSV Export) + runs-on: ubuntu-latest + timeout-minutes: 120 + if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + lfs: true + submodules: recursive + + - name: Cache Unity Editor + uses: actions/cache@v4 + with: + path: /opt/unity/editors + key: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} + + - name: Install Unity + uses: game-ci/unity-installer@v4 + with: + unityVersion: ${{ env.UNITY_VERSION }} + cacheKey: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} + + - name: Cache Library folder + uses: actions/cache@v4 + with: + path: ${{ env.PROJECT_PATH }}/Library + key: library-matrix-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}-${{ hashFiles('**/Packages/**', '**/Packages/manifest.json') }} + + - name: Activate Unity License + if: env.UNITY_LICENSE != '' + uses: game-ci/unity-activate@v3 + with: + license: ${{ env.UNITY_LICENSE }} + unityVersion: ${{ env.UNITY_VERSION }} + + - name: Run Full Matrix (Headless Editor Script) + id: matrix + run: | + cd ${{ env.PROJECT_PATH }} + /opt/unity/editors/${{ env.UNITY_VERSION }}/Editor/Unity \ + -batchmode -nographics -logFile - \ + -projectPath . \ + -executeMethod Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV \ + -matrixOptions '{"Seeds":3,"QuantizeVariants":true,"InterpolateOffVariants":true,"ExtrapolateVariant":true,"TeleportThresholdVariant":true,"CompositeConfigs":true,"MultiObjectScenes":true,"BatchedTransport":true,"RealInterpJob":true,"LateJoinVariant":true,"Dt":0.013888889,"DurationSeconds":6,"SettleSeconds":1.8,"BaseSeed":1523023}' \ + -outputPath ${{ runner.temp }}/sync-sim-matrix.csv + + - name: Upload Matrix CSV + uses: actions/upload-artifact@v4 + with: + name: sync-sim-matrix-csv + path: ${{ runner.temp }}/sync-sim-matrix.csv + retention-days: 30 + + - name: Upload Matrix CSV as Release Asset (on tag) + if: github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/') + uses: softprops/action-gh-release@v1 + with: + files: ${{ runner.temp }}/sync-sim-matrix.csv + + # ─── Lint / Format Check ─── + lint: + name: Code Style (C#) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check formatting (csharpier) + run: | + cd ${{ env.PROJECT_PATH }} + dotnet tool restore + dotnet csharpier --check . \ No newline at end of file diff --git a/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs b/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs index b42ade3d1..286ada6a5 100644 --- a/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs +++ b/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using UnityEngine; namespace Basis.Scripts.Networking.Sync.Testing { @@ -423,6 +424,60 @@ public static string ToCsv(List results) return sb.ToString(); } + /// + /// Command-line entry point for CI: runs the full matrix and writes CSV to the given path. + /// Usage: Unity -batchmode -executeMethod Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV -matrixOptions '{"Seeds":3}' -outputPath /path/to/output.csv + /// + public static void RunAndExportCSV() + { + string matrixOptionsJson = null; + string outputPath = null; + + var args = System.Environment.GetCommandLineArgs(); + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-matrixOptions" && i + 1 < args.Length) + matrixOptionsJson = args[i + 1]; + else if (args[i] == "-outputPath" && i + 1 < args.Length) + outputPath = args[i + 1]; + } + + MatrixOptions options = MatrixOptions.Full(); + if (!string.IsNullOrEmpty(matrixOptionsJson)) + { + try + { + options = JsonUtility.FromJson(matrixOptionsJson); + } + catch (System.Exception e) + { + UnityEngine.Debug.LogError($"Failed to parse -matrixOptions JSON: {e.Message}"); + UnityEditor.EditorApplication.Exit(1); + return; + } + } + + if (string.IsNullOrEmpty(outputPath)) + { + UnityEngine.Debug.LogError("-outputPath is required"); + UnityEditor.EditorApplication.Exit(1); + return; + } + + UnityEngine.Debug.Log($"Running sync sim matrix: {BasisSyncSimMatrix.CountScenarios(options)} scenarios"); + + var results = RunAll(options, (done, total, r) => + { + if (r != null) + UnityEngine.Debug.Log($"[{done}/{total}] {r.ScenarioName} => {(r.Warn ? "WARN" : (r.Pass ? "PASS" : "FAIL"))} {r.FailReason}"); + }, null); + + string csv = ToCsv(results); + System.IO.File.WriteAllText(outputPath, csv); + UnityEngine.Debug.Log($"CSV written to {outputPath} ({results.Count} rows)"); + UnityEditor.EditorApplication.Exit(0); + } + static int Hash(string s) { if (string.IsNullOrEmpty(s)) return 0; @@ -431,4 +486,4 @@ static int Hash(string s) return h & 0x7FFFFFFF; } } -} +} \ No newline at end of file From f7b6c2a23406577a67f4614d0bc698cf222cc983 Mon Sep 17 00:00:00 2001 From: Toys0125 Date: Mon, 29 Jun 2026 02:08:59 +0000 Subject: [PATCH 2/2] Changed with the other workflow as example. --- .github/workflows/sync-sim-tests.yml | 306 ++++++++++-------- .../Editor/SyncTesting/BasisSyncSimMatrix.cs | 43 ++- 2 files changed, 203 insertions(+), 146 deletions(-) diff --git a/.github/workflows/sync-sim-tests.yml b/.github/workflows/sync-sim-tests.yml index bcc869161..ad8091e36 100644 --- a/.github/workflows/sync-sim-tests.yml +++ b/.github/workflows/sync-sim-tests.yml @@ -22,178 +22,198 @@ on: required: false default: 'BasisSyncSimTests' -env: - UNITY_VERSION: ${{ github.event.inputs.unityVersion || '6000.5.1f1' }} - PROJECT_PATH: Basis - TEST_FILTER: ${{ github.event.inputs.testFilter || 'BasisSyncSimTests' }} - TEST_RESULTS_DIR: ${{ runner.temp }}/test-results - UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} - jobs: - test: - name: Unity ${{ env.UNITY_VERSION }} EditMode Tests + check-secret: + name: Check if secrets available + timeout-minutes: 5 runs-on: ubuntu-latest - timeout-minutes: 60 + outputs: + secret-is-set: ${{ steps.secret-is-set.outputs.defined }} + steps: + - name: Check if secret is set, then set variable + id: secret-is-set + env: + TMP_SECRET1: ${{ secrets.UNITY_LICENSE }} + TMP_SECRET2: ${{ secrets.UNITY_EMAIL }} + TMP_SECRET3: ${{ secrets.UNITY_PASSWORD }} + if: "${{ env.TMP_SECRET1 != '' && env.TMP_SECRET2 != '' && env.TMP_SECRET3 != '' }}" + run: echo "defined=true" >> $GITHUB_OUTPUT + test: + name: Unity ${{ github.event.inputs.unityVersion || '6000.5.1f1' }} EditMode Tests + timeout-minutes: 60 + runs-on: ubuntu-latest + permissions: + actions: write # to allow us to manage cache + checks: write # to publish GameCI test checks + contents: read + env: + projectPath: Basis + unityVersion: ${{ github.event.inputs.unityVersion || '6000.5.1f1' }} + testFilter: ${{ github.event.inputs.testFilter || 'BasisSyncSimTests' }} + testArtifactsPath: artifacts/sync-sim-tests + needs: [check-secret] + if: needs.check-secret.outputs.secret-is-set == 'true' steps: - # ─── Checkout ─── - - name: Checkout repository + # We're running out of disk space in some cases. However, the actual test run is happening in a docker container. + # Therefore, we don't actually need most of the tools that github provides. This can save quite a bit of space. + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + tool-cache: true + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: false + - name: "Checkout repository" + timeout-minutes: 10 uses: actions/checkout@v4 with: + fetch-depth: 0 lfs: true submodules: recursive - - # ─── Cache Unity Editor ─── - - name: Cache Unity Editor - uses: actions/cache@v4 - with: - path: /opt/unity/editors - key: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} - restore-keys: | - unity-editor-${{ env.UNITY_VERSION }}- - unity-editor- - - # ─── Install Unity ─── - - name: Install Unity - uses: game-ci/unity-installer@v4 - with: - unityVersion: ${{ env.UNITY_VERSION }} - cacheKey: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} - - # ─── Cache Library ─── - - name: Cache Library folder - uses: actions/cache@v4 - with: - path: ${{ env.PROJECT_PATH }}/Library - key: library-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}-${{ hashFiles('**/Packages/**', '**/Packages/manifest.json') }} - restore-keys: | - library-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}- - library-${{ env.PROJECT_PATH }}- - - # ─── Activate Unity License ─── - - name: Activate Unity License - if: env.UNITY_LICENSE != '' - uses: game-ci/unity-activate@v3 - with: - license: ${{ env.UNITY_LICENSE }} - unityVersion: ${{ env.UNITY_VERSION }} - - # ─── Run EditMode Tests ─── - - name: Run BasisSyncSimTests (EditMode) - id: test + - name: "Restore Library cache" + id: restore-cache + timeout-minutes: 10 + uses: actions/cache/restore@v3 + with: + path: ${{ env.projectPath }}/Library + key: Library-${{ env.projectPath }}-sync-sim-tests-${{ hashFiles(env.projectPath) }} + restore-keys: Library-${{ env.projectPath }}-sync-sim-tests- + - name: "Run BasisSyncSimTests (EditMode)" + timeout-minutes: 60 uses: game-ci/unity-test-runner@v4 env: - UNITY_LICENSE: ${{ env.UNITY_LICENSE }} + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} with: - projectPath: ${{ env.PROJECT_PATH }} - unityVersion: ${{ env.UNITY_VERSION }} + projectPath: ${{ env.projectPath }} + unityVersion: ${{ env.unityVersion }} testMode: editmode - testPlatform: editmode - filters: ${{ env.TEST_FILTER }} - artifactsPath: ${{ env.TEST_RESULTS_DIR }} - checkTestResults: true - customParameters: -logFile - -batchmode -nographics - - # ─── Upload Test Results ─── - - name: Upload test results (NUnit XML) + artifactsPath: ${{ env.testArtifactsPath }} + githubToken: ${{ secrets.GITHUB_TOKEN }} + checkName: Basis Sync Sim EditMode Tests + customParameters: -nographics -testFilter ${{ env.testFilter }} + - name: "Save Library Cache" + uses: actions/cache/save@v3 + if: always() && github.ref_name == 'developer' + with: + path: ${{ env.projectPath }}/Library + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + - name: "Only retain latest cache" + if: always() && github.ref_name == 'developer' + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + OLD_CACHE_IDS=$(gh cache list --sort created_at --key Library-${{ env.projectPath }}-sync-sim-tests- --json id --jq '.[1:] | map(.id) | @sh') + for cache_id in $OLD_CACHE_IDS; do + echo "Deleting cache id: $cache_id" + gh cache delete $cache_id + done + - name: "Upload test artifacts" if: always() uses: actions/upload-artifact@v4 with: - name: test-results-${{ env.UNITY_VERSION }} - path: ${{ env.TEST_RESULTS_DIR }}/*.xml + name: sync-sim-test-artifacts-${{ env.unityVersion }} + path: ${{ env.testArtifactsPath }} retention-days: 30 - # ─── Upload Editor Log (on failure) ─── - - name: Upload Editor.log on failure - if: failure() - uses: actions/upload-artifact@v4 - with: - name: editor-log-${{ env.UNITY_VERSION }} - path: | - ${{ env.PROJECT_PATH }}/Library/Logs/Unity/Editor.log - ${{ runner.temp }}/unity.log - retention-days: 7 - - # ─── Publish Test Report (PR check) ─── - - name: Publish Test Report - if: github.event_name == 'pull_request' - uses: dorny/test-reporter@v1 - with: - name: Unity EditMode Tests - path: ${{ env.TEST_RESULTS_DIR }}/*.xml - reporter: dotnet-trx - fail-on-error: true - - # ─── Matrix Runner (Full Combinatorial) ─── matrix-runner: name: Full Matrix Runner (CSV Export) - runs-on: ubuntu-latest timeout-minutes: 120 - if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' + runs-on: ubuntu-latest + permissions: + actions: write # to allow us to manage cache + contents: write # to upload release assets on tag dispatches + env: + projectPath: Basis + unityVersion: ${{ github.event.inputs.unityVersion || '6000.5.1f1' }} + matrixCsvPath: artifacts/sync-sim-matrix.csv + matrixOptionsPath: artifacts/sync-sim-matrix-options.json + matrixOptions: '{"Seeds":3,"QuantizeVariants":true,"InterpolateOffVariants":true,"ExtrapolateVariant":true,"TeleportThresholdVariant":true,"CompositeConfigs":true,"MultiObjectScenes":true,"BatchedTransport":true,"RealInterpJob":true,"LateJoinVariant":true,"Dt":0.013888889,"DurationSeconds":6,"SettleSeconds":1.8,"BaseSeed":1523023}' + needs: [check-secret] + if: github.event_name == 'workflow_dispatch' && needs.check-secret.outputs.secret-is-set == 'true' steps: - - name: Checkout repository + - name: Free Disk Space (Ubuntu) + uses: jlumbroso/free-disk-space@main + with: + tool-cache: true + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: false + swap-storage: false + - name: "Checkout repository" + timeout-minutes: 10 uses: actions/checkout@v4 with: + fetch-depth: 0 lfs: true submodules: recursive - - - name: Cache Unity Editor - uses: actions/cache@v4 - with: - path: /opt/unity/editors - key: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} - - - name: Install Unity - uses: game-ci/unity-installer@v4 - with: - unityVersion: ${{ env.UNITY_VERSION }} - cacheKey: unity-editor-${{ env.UNITY_VERSION }}-${{ runner.os }} - - - name: Cache Library folder - uses: actions/cache@v4 - with: - path: ${{ env.PROJECT_PATH }}/Library - key: library-matrix-${{ env.PROJECT_PATH }}-${{ env.UNITY_VERSION }}-${{ hashFiles('**/Packages/**', '**/Packages/manifest.json') }} - - - name: Activate Unity License - if: env.UNITY_LICENSE != '' - uses: game-ci/unity-activate@v3 - with: - license: ${{ env.UNITY_LICENSE }} - unityVersion: ${{ env.UNITY_VERSION }} - - - name: Run Full Matrix (Headless Editor Script) - id: matrix + - name: "Restore Library cache" + id: restore-cache + timeout-minutes: 10 + uses: actions/cache/restore@v3 + with: + path: ${{ env.projectPath }}/Library + key: Library-${{ env.projectPath }}-sync-sim-matrix-${{ hashFiles(env.projectPath) }} + restore-keys: Library-${{ env.projectPath }}-sync-sim-matrix- + - name: "Write matrix options" + shell: bash run: | - cd ${{ env.PROJECT_PATH }} - /opt/unity/editors/${{ env.UNITY_VERSION }}/Editor/Unity \ - -batchmode -nographics -logFile - \ - -projectPath . \ - -executeMethod Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV \ - -matrixOptions '{"Seeds":3,"QuantizeVariants":true,"InterpolateOffVariants":true,"ExtrapolateVariant":true,"TeleportThresholdVariant":true,"CompositeConfigs":true,"MultiObjectScenes":true,"BatchedTransport":true,"RealInterpJob":true,"LateJoinVariant":true,"Dt":0.013888889,"DurationSeconds":6,"SettleSeconds":1.8,"BaseSeed":1523023}' \ - -outputPath ${{ runner.temp }}/sync-sim-matrix.csv - - - name: Upload Matrix CSV + mkdir -p "$(dirname "${{ env.matrixOptionsPath }}")" + cat > "${{ env.matrixOptionsPath }}" <<'JSON' + ${{ env.matrixOptions }} + JSON + - name: "Run Full Matrix (Headless Editor Script)" + timeout-minutes: 120 + uses: BasisVR/unity-builder@main + env: + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} + with: + buildName: sync-sim-matrix + buildsPath: artifacts/matrix-build + buildMethod: Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV + customParameters: -matrixOptionsPath /github/workspace/${{ env.matrixOptionsPath }} -outputPath /github/workspace/${{ env.matrixCsvPath }} + manualExit: true + projectPath: ${{ env.projectPath }} + targetPlatform: StandaloneLinux64 + unityVersion: ${{ env.unityVersion }} + versioning: None + linux64RemoveExecutableExtension: false + - name: "Save Library Cache" + uses: actions/cache/save@v3 + if: always() && github.ref_name == 'developer' + with: + path: ${{ env.projectPath }}/Library + key: ${{ steps.restore-cache.outputs.cache-primary-key }} + - name: "Only retain latest cache" + if: always() && github.ref_name == 'developer' + shell: bash + env: + GH_TOKEN: ${{ github.token }} + run: | + OLD_CACHE_IDS=$(gh cache list --sort created_at --key Library-${{ env.projectPath }}-sync-sim-matrix- --json id --jq '.[1:] | map(.id) | @sh') + for cache_id in $OLD_CACHE_IDS; do + echo "Deleting cache id: $cache_id" + gh cache delete $cache_id + done + - name: "Upload Matrix CSV" + if: always() uses: actions/upload-artifact@v4 with: name: sync-sim-matrix-csv - path: ${{ runner.temp }}/sync-sim-matrix.csv + path: ${{ env.matrixCsvPath }} retention-days: 30 - - - name: Upload Matrix CSV as Release Asset (on tag) + - name: "Upload Matrix CSV as Release Asset (on tag)" if: github.event_name == 'workflow_dispatch' && startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: - files: ${{ runner.temp }}/sync-sim-matrix.csv - - # ─── Lint / Format Check ─── - lint: - name: Code Style (C#) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Check formatting (csharpier) - run: | - cd ${{ env.PROJECT_PATH }} - dotnet tool restore - dotnet csharpier --check . \ No newline at end of file + files: ${{ env.matrixCsvPath }} diff --git a/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs b/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs index 286ada6a5..afc3e0adc 100644 --- a/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs +++ b/Basis/Packages/com.basis.framework/Editor/SyncTesting/BasisSyncSimMatrix.cs @@ -23,6 +23,7 @@ public sealed class FieldConfig public bool PositionFirst; } + [Serializable] public sealed class MatrixOptions { public bool QuantizeVariants = true; @@ -427,10 +428,12 @@ public static string ToCsv(List results) /// /// Command-line entry point for CI: runs the full matrix and writes CSV to the given path. /// Usage: Unity -batchmode -executeMethod Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV -matrixOptions '{"Seeds":3}' -outputPath /path/to/output.csv + /// Unity -batchmode -executeMethod Basis.Scripts.Networking.Sync.Testing.BasisSyncSimMatrix.RunAndExportCSV -matrixOptionsPath /path/to/options.json -outputPath /path/to/output.csv /// public static void RunAndExportCSV() { string matrixOptionsJson = null; + string matrixOptionsPath = null; string outputPath = null; var args = System.Environment.GetCommandLineArgs(); @@ -438,16 +441,32 @@ public static void RunAndExportCSV() { if (args[i] == "-matrixOptions" && i + 1 < args.Length) matrixOptionsJson = args[i + 1]; + else if (args[i] == "-matrixOptionsPath" && i + 1 < args.Length) + matrixOptionsPath = args[i + 1]; else if (args[i] == "-outputPath" && i + 1 < args.Length) outputPath = args[i + 1]; } + if (!string.IsNullOrEmpty(matrixOptionsPath)) + { + try + { + matrixOptionsJson = System.IO.File.ReadAllText(matrixOptionsPath); + } + catch (System.Exception e) + { + UnityEngine.Debug.LogError($"Failed to read -matrixOptionsPath '{matrixOptionsPath}': {e.Message}"); + UnityEditor.EditorApplication.Exit(1); + return; + } + } + MatrixOptions options = MatrixOptions.Full(); if (!string.IsNullOrEmpty(matrixOptionsJson)) { try { - options = JsonUtility.FromJson(matrixOptionsJson); + JsonUtility.FromJsonOverwrite(matrixOptionsJson, options); } catch (System.Exception e) { @@ -473,8 +492,26 @@ public static void RunAndExportCSV() }, null); string csv = ToCsv(results); + string outputDirectory = System.IO.Path.GetDirectoryName(outputPath); + if (!string.IsNullOrEmpty(outputDirectory)) + System.IO.Directory.CreateDirectory(outputDirectory); System.IO.File.WriteAllText(outputPath, csv); - UnityEngine.Debug.Log($"CSV written to {outputPath} ({results.Count} rows)"); + + int failed = 0; + for (int i = 0; i < results.Count; i++) + { + if (!results[i].Pass) + failed++; + } + + UnityEngine.Debug.Log($"CSV written to {outputPath} ({results.Count} rows, {failed} failures)"); + if (failed > 0) + { + UnityEngine.Debug.LogError($"Sync sim matrix completed with {failed} failing rows. See CSV for details."); + UnityEditor.EditorApplication.Exit(1); + return; + } + UnityEditor.EditorApplication.Exit(0); } @@ -486,4 +523,4 @@ static int Hash(string s) return h & 0x7FFFFFFF; } } -} \ No newline at end of file +}