77 workflow_dispatch :
88 inputs :
99 pr_number :
10- description : ' Pull Request Number'
10+ description : " Pull Request Number"
1111 required : false
12- default : ' '
12+ default : " "
1313
1414name : CI
1515
@@ -19,6 +19,7 @@ concurrency:
1919
2020jobs :
2121 docker_smoketests :
22+ needs : [lints]
2223 name : Smoketests
2324 strategy :
2425 matrix :
6970 with :
7071 global-json-file : global.json
7172
73+ - name : Override NuGet packages
74+ shell : bash
75+ run : |
76+ dotnet pack -c Release crates/bindings-csharp/BSATN.Runtime
77+ dotnet pack -c Release crates/bindings-csharp/Runtime
78+ cd sdks/csharp
79+ ./tools~/write-nuget-config.sh ../..
80+
7281 # nodejs and pnpm are required for the typescript quickstart smoketest
7382 - name : Set up Node.js
7483 uses : actions/setup-node@v4
@@ -108,7 +117,7 @@ jobs:
108117 dotnet workload config --update-mode manifests
109118 dotnet workload update
110119 - uses : actions/setup-python@v5
111- with : { python-version: ' 3.12' }
120+ with : { python-version: " 3.12" }
112121 if : runner.os == 'Windows'
113122 - name : Install python deps
114123 run : python -m pip install -r smoketests/requirements.txt
@@ -120,6 +129,7 @@ jobs:
120129 run : docker compose -f .github/docker-compose.yml down
121130
122131 test :
132+ needs : [lints]
123133 name : Test Suite
124134 runs-on : spacetimedb-new-runner
125135 container :
@@ -500,19 +510,48 @@ jobs:
500510 run : |
501511 cargo ci cli-docs
502512
513+ llm_ci_check :
514+ name : Verify LLM benchmark is up to date
515+ permissions :
516+ contents : read
517+ runs-on : ubuntu-latest
518+ # Disable the tests because they are causing us headaches with merge conflicts and re-runs etc.
519+ if : false
520+ steps :
521+ # Build the tool from master to ensure consistent hash computation
522+ # with the llm-benchmark-update workflow (which also uses master's tool).
523+ - name : Checkout master (build tool from trusted code)
524+ uses : actions/checkout@v4
525+ with :
526+ ref : master
527+ fetch-depth : 1
528+
529+ - uses : dtolnay/rust-toolchain@stable
530+ - uses : Swatinem/rust-cache@v2
531+
532+ - name : Install llm-benchmark tool from master
533+ run : |
534+ cargo install --path tools/xtask-llm-benchmark --locked
535+ command -v llm_benchmark
536+
537+ # Now checkout the PR branch to verify its benchmark files
538+ - name : Checkout PR branch
539+ uses : actions/checkout@v4
540+ with :
541+ clean : false
542+
543+ - name : Run hash check (both langs)
544+ run : llm_benchmark ci-check
545+
503546 unity-testsuite :
547+ needs : [lints]
504548 # Skip if this is an external contribution.
505549 # The license secrets will be empty, so the step would fail anyway.
506550 if : ${{ github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork }}
507551 permissions :
508552 contents : read
509553 checks : write
510- runs-on : spacetimedb-new-runner
511- container :
512- image : localhost:5000/spacetimedb-ci:latest
513- options : >-
514- --privileged
515- --cgroupns=host
554+ runs-on : spacetimedb-unity-runner
516555 timeout-minutes : 30
517556 env :
518557 CARGO_TARGET_DIR : ${{ github.workspace }}/target
@@ -542,6 +581,10 @@ jobs:
542581 cd sdks/csharp
543582 ./tools~/write-nuget-config.sh ../..
544583
584+ - name : Restore .NET solution
585+ working-directory : sdks/csharp
586+ run : dotnet restore --configfile NuGet.Config SpacetimeDB.ClientSDK.sln
587+
545588 # Now, setup the Unity tests.
546589 - name : Patch spacetimedb dependency in Cargo.toml
547590 working-directory : demo/Blackholio/server-rust
@@ -579,13 +622,16 @@ jobs:
579622 exit 1
580623 }
581624
625+ - name : Hydrate Unity SDK DLLs
626+ run : cargo ci dlls
627+
582628 - name : Check Unity meta files
583629 uses : DeNA/unity-meta-check@v3
584630 with :
585631 enable_pr_comment : ${{ github.event_name == 'pull_request' }}
586632 target_path : sdks/csharp
587633 env :
588- GITHUB_TOKEN : ' ${{ secrets.GITHUB_TOKEN }}'
634+ GITHUB_TOKEN : " ${{ secrets.GITHUB_TOKEN }}"
589635
590636 - name : Start SpacetimeDB
591637 run : |
@@ -601,10 +647,7 @@ jobs:
601647 - name : Patch com.clockworklabs.spacetimedbsdk dependency in manifest.json
602648 working-directory : demo/Blackholio/client-unity/Packages
603649 run : |
604- # Replace the com.clockworklabs.spacetimedbsdk dependency with the current branch.
605- # Note: Pointing to a local directory does not work, because our earlier steps nuke our meta files, which then causes Unity to not properly respect the DLLs (e.g.
606- # codegen does not work properly).
607- yq e -i '.dependencies["com.clockworklabs.spacetimedbsdk"] = "https://github.com/clockworklabs/SpacetimeDB.git?path=sdks/csharp#${{ github.head_ref }}"' manifest.json
650+ yq e -i '.dependencies["com.clockworklabs.spacetimedbsdk"] = "file:../../../../sdks/csharp"' manifest.json
608651 cat manifest.json
609652
610653 - uses : actions/cache@v3
@@ -613,9 +656,6 @@ jobs:
613656 key : Unity-${{ github.head_ref }}
614657 restore-keys : Unity-
615658
616- # We need this to support "Docker in Docker"
617- - name : Start Docker daemon
618- run : /usr/local/bin/start-docker.sh
619659 - name : Run Unity tests
620660 uses : game-ci/unity-test-runner@v4
621661 with :
@@ -624,13 +664,14 @@ jobs:
624664 githubToken : ${{ secrets.GITHUB_TOKEN }}
625665 testMode : playmode
626666 useHostNetwork : true
627- artifactsPath : ' '
667+ artifactsPath : " "
628668 env :
629669 UNITY_EMAIL : ${{ secrets.UNITY_EMAIL }}
630670 UNITY_PASSWORD : ${{ secrets.UNITY_PASSWORD }}
631671 UNITY_SERIAL : ${{ secrets.UNITY_SERIAL }}
632672
633673 csharp-testsuite :
674+ needs : [lints]
634675 runs-on : spacetimedb-new-runner
635676 container :
636677 image : localhost:5000/spacetimedb-ci:latest
@@ -666,9 +707,13 @@ jobs:
666707 cd sdks/csharp
667708 ./tools~/write-nuget-config.sh ../..
668709
710+ - name : Restore .NET solution
711+ working-directory : sdks/csharp
712+ run : dotnet restore --configfile NuGet.Config SpacetimeDB.ClientSDK.sln
713+
669714 - name : Run .NET tests
670715 working-directory : sdks/csharp
671- run : dotnet test -warnaserror
716+ run : dotnet test -warnaserror --no-restore
672717
673718 - name : Verify C# formatting
674719 working-directory : sdks/csharp
@@ -737,3 +782,129 @@ jobs:
737782 echo 'Error: Bindings are dirty. Please run `sdks/csharp/tools~/gen-regression-tests.sh`.'
738783 exit 1
739784 }
785+
786+ internal-tests :
787+ name : Internal Tests
788+ needs : [lints]
789+ # Skip if not a PR or a push to master
790+ # Skip if this is an external contribution. GitHub secrets will be empty, so the step would fail anyway.
791+ if : ${{ (github.event_name == 'pull_request' || (github.event_name == 'push' && github.ref == 'refs/heads/master'))
792+ && (github.event_name != 'pull_request' || !github.event.pull_request.head.repo.fork) }}
793+ permissions :
794+ contents : read
795+ runs-on : ubuntu-latest
796+ env :
797+ TARGET_OWNER : clockworklabs
798+ TARGET_REPO : SpacetimeDBPrivate
799+ steps :
800+ - id : dispatch
801+ name : Trigger tests
802+ uses : actions/github-script@v7
803+ with :
804+ github-token : ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }}
805+ script : |
806+ const workflowId = 'ci.yml';
807+ const targetRef = 'master';
808+ const targetOwner = process.env.TARGET_OWNER;
809+ const targetRepo = process.env.TARGET_REPO;
810+ // Use the ref for pull requests because the head sha is brittle (github does some extra dance where it merges in master).
811+ const publicRef = (context.eventName === 'pull_request') ? context.payload.pull_request.head.ref : context.sha;
812+ const preDispatch = new Date().toISOString();
813+
814+ // Dispatch the workflow in the target repository
815+ await github.rest.actions.createWorkflowDispatch({
816+ owner : targetOwner,
817+ repo : targetRepo,
818+ workflow_id : workflowId,
819+ ref : targetRef,
820+ inputs : { public_ref: publicRef }
821+ });
822+
823+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
824+
825+ // Find the dispatched run by name
826+ let runId = null;
827+ for (let attempt = 0; attempt < 20 && !runId; attempt++) { // up to ~10 minutes to locate the run
828+ await sleep(5000);
829+ const runsResp = await github.rest.actions.listWorkflowRuns({
830+ owner : targetOwner,
831+ repo : targetRepo,
832+ workflow_id : workflowId,
833+ event : ' workflow_dispatch' ,
834+ branch : targetRef,
835+ per_page : 50,
836+ });
837+
838+ const expectedName = `CI [public_ref=${publicRef}]`;
839+ const candidates = runsResp.data.workflow_runs
840+ .filter(r => r.name === expectedName && new Date(r.created_at) >= new Date(preDispatch))
841+ .sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
842+
843+ if (candidates.length > 0) {
844+ runId = candidates[0].id;
845+ break;
846+ }
847+ }
848+
849+ if (!runId) {
850+ core.setFailed('Failed to locate dispatched run in the private repository.');
851+ return;
852+ }
853+
854+ const runUrl = `https://github.com/${targetOwner}/${targetRepo}/actions/runs/${runId}`;
855+ core.info(`View run : ${runUrl}`);
856+ core.setOutput('run_id', String(runId));
857+ core.setOutput('run_url', runUrl);
858+
859+ - name : Wait for Internal Tests to complete
860+ uses : actions/github-script@v7
861+ with :
862+ github-token : ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }}
863+ script : |
864+ const targetOwner = process.env.TARGET_OWNER;
865+ const targetRepo = process.env.TARGET_REPO;
866+ const runId = Number(`${{ steps.dispatch.outputs.run_id }}`);
867+ const runUrl = `${{ steps.dispatch.outputs.run_url }}`;
868+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
869+
870+ core.info(`Waiting for workflow result... ${runUrl}`);
871+
872+ let conclusion = null;
873+ for (let attempt = 0; attempt < 240; attempt++) { // up to ~2 hours
874+ const runResp = await github.rest.actions.getWorkflowRun({
875+ owner : targetOwner,
876+ repo : targetRepo,
877+ run_id : runId
878+ });
879+ const { status, conclusion : c } = runResp.data;
880+ if (status === 'completed') {
881+ conclusion = c || 'success';
882+ break;
883+ }
884+ await sleep(30000);
885+ }
886+
887+ if (!conclusion) {
888+ core.setFailed('Timed out waiting for private workflow to complete.');
889+ return;
890+ }
891+
892+ if (conclusion !== 'success') {
893+ core.setFailed(`Private workflow failed with conclusion : ${conclusion}`);
894+ }
895+
896+ - name : Cancel invoked run if workflow cancelled
897+ if : ${{ cancelled() }}
898+ uses : actions/github-script@v7
899+ with :
900+ github-token : ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }}
901+ script : |
902+ const targetOwner = process.env.TARGET_OWNER;
903+ const targetRepo = process.env.TARGET_REPO;
904+ const runId = Number(`${{ steps.dispatch.outputs.run_id }}`);
905+ if (!runId) return;
906+ await github.rest.actions.cancelWorkflowRun({
907+ owner: targetOwner,
908+ repo: targetRepo,
909+ run_id: runId,
910+ });
0 commit comments