1010 merge_group :
1111 branches : [main]
1212 types : [checks_requested]
13+ # Manual trigger for on-demand E2E runs on the self-hosted GPU runners, without
14+ # waiting on a push/PR or the full gate. Dispatch against any ref
15+ # (`gh workflow run ci.yml --ref <branch> -f platform=... -f tier=...`) — GitHub
16+ # runs THAT ref's copy of this file, so the E2E jobs it selects live on the ref.
17+ # A dispatch skips build-and-test (see its `if:`) for a fast loop. This trigger
18+ # must exist on the default branch for the workflow to be dispatchable at all.
19+ workflow_dispatch :
20+ inputs :
21+ platform :
22+ description : Which runner(s) to target
23+ type : choice
24+ default : all
25+ options : [all, mock, app-dev-gpu, strix-ubuntu, strix-windows]
26+ tier :
27+ description : Which scenario tier(s) to run
28+ type : choice
29+ default : both
30+ options : [both, expect-pass, known-bugs]
1331
1432concurrency :
1533 group : ${{ github.workflow }}-${{ github.ref }}
@@ -109,6 +127,9 @@ jobs:
109127 runs-on : ubuntu-latest
110128 # Don't spend per-OS build/test cycles unless the cheap lint gate is green.
111129 needs : [changes, clippy, prek]
130+ # A manual E2E dispatch skips this heavy job for a fast loop; the E2E jobs
131+ # tolerate a skipped build-and-test in their own `if:` guards.
132+ if : github.event_name != 'workflow_dispatch'
112133 steps :
113134 - uses : actions/checkout@v6
114135
@@ -541,7 +562,20 @@ jobs:
541562 name : E2E tests
542563 runs-on : ubuntu-latest
543564 needs : [changes, build-and-test]
544- if : needs.changes.outputs.heavy == 'true'
565+ # On push/PR/merge_group: unchanged — run when build-and-test succeeded and
566+ # the change is heavy. On workflow_dispatch: build-and-test is skipped, so
567+ # tolerate that and gate on the platform/tier inputs instead (mock tier here).
568+ if : >-
569+ always()
570+ && needs.changes.result == 'success'
571+ && (
572+ (github.event_name != 'workflow_dispatch'
573+ && needs.build-and-test.result == 'success'
574+ && needs.changes.outputs.heavy == 'true')
575+ || (github.event_name == 'workflow_dispatch'
576+ && (inputs.platform == 'all' || inputs.platform == 'mock')
577+ && (inputs.tier == 'both' || inputs.tier == 'expect-pass'))
578+ )
545579 steps :
546580 - uses : actions/checkout@v6
547581
@@ -576,7 +610,18 @@ jobs:
576610 name : E2E tests (known bugs)
577611 runs-on : ubuntu-latest
578612 needs : [changes, build-and-test]
579- if : needs.changes.outputs.heavy == 'true'
613+ # See `e2e`: dispatch tolerates skipped build-and-test; mock tier, known-bugs.
614+ if : >-
615+ always()
616+ && needs.changes.result == 'success'
617+ && (
618+ (github.event_name != 'workflow_dispatch'
619+ && needs.build-and-test.result == 'success'
620+ && needs.changes.outputs.heavy == 'true')
621+ || (github.event_name == 'workflow_dispatch'
622+ && (inputs.platform == 'all' || inputs.platform == 'mock')
623+ && (inputs.tier == 'both' || inputs.tier == 'known-bugs'))
624+ )
580625 steps :
581626 - uses : actions/checkout@v6
582627
@@ -603,7 +648,18 @@ jobs:
603648 name : E2E tests (GPU)
604649 runs-on : [self-hosted, linux, amd-gpu]
605650 needs : [changes, build-and-test]
606- if : needs.changes.outputs.heavy == 'true'
651+ # See `e2e`: dispatch tolerates skipped build-and-test; app-dev-gpu, expect-pass.
652+ if : >-
653+ always()
654+ && needs.changes.result == 'success'
655+ && (
656+ (github.event_name != 'workflow_dispatch'
657+ && needs.build-and-test.result == 'success'
658+ && needs.changes.outputs.heavy == 'true')
659+ || (github.event_name == 'workflow_dispatch'
660+ && (inputs.platform == 'all' || inputs.platform == 'app-dev-gpu')
661+ && (inputs.tier == 'both' || inputs.tier == 'expect-pass'))
662+ )
607663 continue-on-error : true
608664 steps :
609665 - uses : actions/checkout@v6
@@ -629,7 +685,18 @@ jobs:
629685 name : E2E tests (GPU, known bugs)
630686 runs-on : [self-hosted, linux, amd-gpu]
631687 needs : [changes, build-and-test]
632- if : needs.changes.outputs.heavy == 'true'
688+ # See `e2e`: dispatch tolerates skipped build-and-test; app-dev-gpu, known-bugs.
689+ if : >-
690+ always()
691+ && needs.changes.result == 'success'
692+ && (
693+ (github.event_name != 'workflow_dispatch'
694+ && needs.build-and-test.result == 'success'
695+ && needs.changes.outputs.heavy == 'true')
696+ || (github.event_name == 'workflow_dispatch'
697+ && (inputs.platform == 'all' || inputs.platform == 'app-dev-gpu')
698+ && (inputs.tier == 'both' || inputs.tier == 'known-bugs'))
699+ )
633700 continue-on-error : true
634701 steps :
635702 - uses : actions/checkout@v6
@@ -654,7 +721,18 @@ jobs:
654721 name : E2E tests (Strix Halo, Ubuntu)
655722 runs-on : [self-hosted, linux, strix-halo]
656723 needs : [changes, build-and-test]
657- if : needs.changes.outputs.heavy == 'true'
724+ # See `e2e`: dispatch tolerates skipped build-and-test; strix-ubuntu, expect-pass.
725+ if : >-
726+ always()
727+ && needs.changes.result == 'success'
728+ && (
729+ (github.event_name != 'workflow_dispatch'
730+ && needs.build-and-test.result == 'success'
731+ && needs.changes.outputs.heavy == 'true')
732+ || (github.event_name == 'workflow_dispatch'
733+ && (inputs.platform == 'all' || inputs.platform == 'strix-ubuntu')
734+ && (inputs.tier == 'both' || inputs.tier == 'expect-pass'))
735+ )
658736 continue-on-error : true
659737 # The runner's root disk is full and non-persistent; keep the toolchain
660738 # download, install, and temp files on the persistent runner directory so
@@ -685,7 +763,18 @@ jobs:
685763 name : E2E tests (Strix Halo, Ubuntu, known bugs)
686764 runs-on : [self-hosted, linux, strix-halo]
687765 needs : [changes, build-and-test]
688- if : needs.changes.outputs.heavy == 'true'
766+ # See `e2e`: dispatch tolerates skipped build-and-test; strix-ubuntu, known-bugs.
767+ if : >-
768+ always()
769+ && needs.changes.result == 'success'
770+ && (
771+ (github.event_name != 'workflow_dispatch'
772+ && needs.build-and-test.result == 'success'
773+ && needs.changes.outputs.heavy == 'true')
774+ || (github.event_name == 'workflow_dispatch'
775+ && (inputs.platform == 'all' || inputs.platform == 'strix-ubuntu')
776+ && (inputs.tier == 'both' || inputs.tier == 'known-bugs'))
777+ )
689778 continue-on-error : true
690779 # See e2e-gpu-strix-ubuntu: root disk is full/non-persistent, so keep the
691780 # toolchain and temp files on the persistent runner directory.
@@ -719,12 +808,36 @@ jobs:
719808 name : E2E tests (Strix Halo, Windows)
720809 runs-on : [self-hosted, windows, strix-halo]
721810 needs : [changes, build-and-test]
722- if : needs.changes.outputs.heavy == 'true'
811+ # See `e2e`: dispatch tolerates skipped build-and-test; strix-windows, expect-pass.
812+ if : >-
813+ always()
814+ && needs.changes.result == 'success'
815+ && (
816+ (github.event_name != 'workflow_dispatch'
817+ && needs.build-and-test.result == 'success'
818+ && needs.changes.outputs.heavy == 'true')
819+ || (github.event_name == 'workflow_dispatch'
820+ && (inputs.platform == 'all' || inputs.platform == 'strix-windows')
821+ && (inputs.tier == 'both' || inputs.tier == 'expect-pass'))
822+ )
723823 continue-on-error : true
724824 steps :
725825 - uses : actions/checkout@v6
726826
727- - uses : actions-rust-lang/setup-rust-toolchain@v1
827+ # setup-rust-toolchain runs an internal bash script, which this Windows
828+ # runner lacks (bash: command not found). Bootstrap rustup with the
829+ # PowerShell-native installer instead; idempotent, so it only downloads on
830+ # a runner that doesn't already have the toolchain.
831+ - name : Ensure Rust toolchain (PowerShell)
832+ shell : pwsh
833+ run : |
834+ if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
835+ Invoke-WebRequest https://win.rustup.rs/x86_64 -OutFile $env:TEMP\rustup-init.exe
836+ # --default-toolchain none: rust-toolchain.toml pins the exact
837+ # version (1.96.0 + components), auto-installed on first cargo use.
838+ & $env:TEMP\rustup-init.exe -y --default-toolchain none
839+ "$env:USERPROFILE\.cargo\bin" | Out-File -FilePath $env:GITHUB_PATH -Append
840+ }
728841
729842 - name : Run E2E tests on Strix Halo Windows (excluding known bugs)
730843 shell : pwsh
@@ -741,12 +854,34 @@ jobs:
741854 name : E2E tests (Strix Halo, Windows, known bugs)
742855 runs-on : [self-hosted, windows, strix-halo]
743856 needs : [changes, build-and-test]
744- if : needs.changes.outputs.heavy == 'true'
857+ # See `e2e`: dispatch tolerates skipped build-and-test; strix-windows, known-bugs.
858+ if : >-
859+ always()
860+ && needs.changes.result == 'success'
861+ && (
862+ (github.event_name != 'workflow_dispatch'
863+ && needs.build-and-test.result == 'success'
864+ && needs.changes.outputs.heavy == 'true')
865+ || (github.event_name == 'workflow_dispatch'
866+ && (inputs.platform == 'all' || inputs.platform == 'strix-windows')
867+ && (inputs.tier == 'both' || inputs.tier == 'known-bugs'))
868+ )
745869 continue-on-error : true
746870 steps :
747871 - uses : actions/checkout@v6
748872
749- - uses : actions-rust-lang/setup-rust-toolchain@v1
873+ # See e2e-gpu-strix-windows: bootstrap rustup via PowerShell because this
874+ # runner has no bash for setup-rust-toolchain's internal script.
875+ - name : Ensure Rust toolchain (PowerShell)
876+ shell : pwsh
877+ run : |
878+ if (-not (Get-Command cargo -ErrorAction SilentlyContinue)) {
879+ Invoke-WebRequest https://win.rustup.rs/x86_64 -OutFile $env:TEMP\rustup-init.exe
880+ # --default-toolchain none: rust-toolchain.toml pins the exact
881+ # version (1.96.0 + components), auto-installed on first cargo use.
882+ & $env:TEMP\rustup-init.exe -y --default-toolchain none
883+ "$env:USERPROFILE\.cargo\bin" | Out-File -FilePath $env:GITHUB_PATH -Append
884+ }
750885
751886 - name : Run known-bug E2E scenarios on Strix Halo Windows
752887 shell : pwsh
@@ -782,7 +917,12 @@ jobs:
782917 - e2e-gpu-strix-ubuntu-known-bugs
783918 - e2e-gpu-strix-windows
784919 - e2e-gpu-strix-windows-known-bugs
785- if : always() && needs.changes.outputs.heavy == 'true'
920+ # Consolidate whatever ran. On dispatch `heavy` is unset, so also run when the
921+ # trigger was manual; `always()` still lets it collect partial/failed tiers.
922+ if : >-
923+ always()
924+ && (needs.changes.outputs.heavy == 'true'
925+ || github.event_name == 'workflow_dispatch')
786926 steps :
787927 - uses : actions/checkout@v6
788928
0 commit comments