mirror of
https://github.com/stride3d/stride.git
synced 2026-10-12 02:23:23 +00:00
321 lines
13 KiB
YAML
321 lines
13 KiB
YAML
name: CI
|
||
|
||
on:
|
||
push:
|
||
branches:
|
||
- master
|
||
paths:
|
||
- '.github/workflows/**'
|
||
- 'build/**'
|
||
- 'deps/**'
|
||
- 'sources/**'
|
||
- 'tests/**'
|
||
- '!**/.all-contributorsrc'
|
||
- '!**/.editorconfig'
|
||
- '!**/.gitignore'
|
||
- '!**/*.md'
|
||
- '!crowdin.yml'
|
||
# No paths filter here: the Gate job is a required check, so CI must report on every PR.
|
||
# The changes job's filters skip the actual work for out-of-scope PRs.
|
||
pull_request:
|
||
# Label changes are handled by pr-label-suites.yml, not here (to avoid restarting
|
||
# many workflows on label change); a `ci-run-on-draft` label takes effect on the next push.
|
||
types: [opened, synchronize, reopened, ready_for_review]
|
||
workflow_dispatch:
|
||
inputs:
|
||
ios:
|
||
description: Run iOS jobs
|
||
type: boolean
|
||
default: true
|
||
android:
|
||
description: Run Android jobs
|
||
type: boolean
|
||
default: true
|
||
macos:
|
||
description: Run macOS jobs
|
||
type: boolean
|
||
default: true
|
||
|
||
permissions:
|
||
checks: write
|
||
contents: read
|
||
pull-requests: read
|
||
|
||
concurrency:
|
||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
|
||
|
||
jobs:
|
||
# Per-area path-filter outputs drive the per-job `if:` conditions below.
|
||
# Defaults to 'true' for non-pull_request triggers (workflow_dispatch, push to master)
|
||
# so those run everything regardless of which files changed.
|
||
#
|
||
# Fork-friendly: upstream stride3d/stride always runs (the repository-name clause covers
|
||
# both direct pushes and fork→upstream PRs, where base-repo `vars` aren't readable from a
|
||
# fork PR's context). On forks, push/PR only run when STRIDE_ENABLE_PUSH_CI is set on the
|
||
# fork. workflow_dispatch always punches through so manual runs work anywhere. Downstream
|
||
# jobs `needs: changes`, so this single guard cascades — no per-job edits needed.
|
||
changes:
|
||
if: >
|
||
(github.event_name != 'push' && github.event_name != 'pull_request')
|
||
|| github.repository == 'stride3d/stride'
|
||
|| vars.STRIDE_ENABLE_PUSH_CI == 'true'
|
||
uses: ./.github/workflows/changes.yml
|
||
|
||
# Draft PRs skip all automatic CI to save runner minutes. Add a `ci-run-on-draft` label to
|
||
# run the normal path-gated suites while iterating, or a `ci-<suite>` label (see
|
||
# pr-label-suites.yml) for a specific opt-in suite. ready_for_review re-runs everything.
|
||
### Misc ###
|
||
Assembly-Processor:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && (needs.changes.outputs.runtime == 'true' || needs.changes.outputs.full == 'true')
|
||
uses: ./.github/workflows/build-assembly-processor.yml
|
||
with:
|
||
build-type: Release
|
||
|
||
VS-Package:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.full == 'true'
|
||
uses: ./.github/workflows/build-vspackage.yml
|
||
with:
|
||
build-type: Debug # Release has a bug and cannot build
|
||
|
||
### Runtimes ###
|
||
# The `ios` filter is narrower than `runtime` on purpose: iOS runners are costly, macOS-Tests-Game
|
||
# covers the shared engine surface per-PR, and master pushes run this per-commit anyway.
|
||
iOS-Runtime:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.ios == 'true' && (github.event_name != 'workflow_dispatch' || inputs.ios)
|
||
uses: ./.github/workflows/build-ios.yml
|
||
with:
|
||
build-type: Release
|
||
|
||
Android-Runtime:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true' && (github.event_name != 'workflow_dispatch' || inputs.android)
|
||
uses: ./.github/workflows/build-android.yml
|
||
with:
|
||
build-type: Release
|
||
|
||
Linux-Runtime:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true'
|
||
uses: ./.github/workflows/build-linux-runtime.yml
|
||
with:
|
||
build-type: Release
|
||
|
||
Windows-Runtime-D3D11:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true'
|
||
uses: ./.github/workflows/build-windows-runtime.yml
|
||
with:
|
||
build-type: Release
|
||
graphics-api: Direct3D11
|
||
|
||
Windows-Runtime-D3D12:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true'
|
||
uses: ./.github/workflows/build-windows-runtime.yml
|
||
with:
|
||
build-type: Release
|
||
graphics-api: Direct3D12
|
||
|
||
Windows-Runtime-Vulkan:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true'
|
||
uses: ./.github/workflows/build-windows-runtime.yml
|
||
with:
|
||
build-type: Release
|
||
graphics-api: Vulkan
|
||
|
||
# Null ships no renderer, so nothing else builds it and its stubs drift out of step with the shared
|
||
# signatures they implement. Compiling it here is what keeps that API honest.
|
||
Windows-Runtime-Null:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.runtime == 'true'
|
||
uses: ./.github/workflows/build-windows-runtime.yml
|
||
with:
|
||
build-type: Release
|
||
graphics-api: "Null"
|
||
|
||
### Full Windows build (engine + editor + assets + samples) ###
|
||
Windows-Full:
|
||
needs: changes
|
||
if: (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft')) && needs.changes.outputs.full == 'true'
|
||
uses: ./.github/workflows/build-windows-full.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
### Tests ###
|
||
# Game tests where the picked graphics API doesn't materially affect outcomes
|
||
# (physics, audio, asset, engine logic). One run with D3D11 is sufficient.
|
||
Windows-Tests-Game-ApiNeutral:
|
||
needs: [changes, Windows-Runtime-D3D11]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'failure'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-windows-game-api-neutral.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
# Tests-Simple smoke-tests non-graphics paths; pinned to D3D11 build as the gate.
|
||
Windows-Tests-Simple:
|
||
needs: [changes, Windows-Runtime-D3D11]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'failure'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-windows-simple.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
Windows-Tests-Game-D3D11:
|
||
needs: [changes, Windows-Runtime-D3D11]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'failure'
|
||
&& needs['Windows-Runtime-D3D11'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-windows-game.yml
|
||
with:
|
||
build-type: Debug
|
||
graphics-api: Direct3D11
|
||
|
||
Windows-Tests-Game-D3D12:
|
||
needs: [changes, Windows-Runtime-D3D12]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Windows-Runtime-D3D12'].result != 'failure'
|
||
&& needs['Windows-Runtime-D3D12'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-windows-game.yml
|
||
with:
|
||
build-type: Debug
|
||
graphics-api: Direct3D12
|
||
|
||
Windows-Tests-Game-Vulkan:
|
||
needs: [changes, Windows-Runtime-Vulkan]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Windows-Runtime-Vulkan'].result != 'failure'
|
||
&& needs['Windows-Runtime-Vulkan'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-windows-game.yml
|
||
with:
|
||
build-type: Debug
|
||
graphics-api: Vulkan
|
||
|
||
Linux-Tests-Simple:
|
||
needs: [changes, Linux-Runtime]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Linux-Runtime'].result != 'failure'
|
||
&& needs['Linux-Runtime'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-linux-simple.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
Linux-Tests-Game:
|
||
needs: [changes, Linux-Runtime]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Linux-Runtime'].result != 'failure'
|
||
&& needs['Linux-Runtime'].result != 'cancelled'
|
||
uses: ./.github/workflows/test-linux-game.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
# macOS runners bill ~10× Linux on GitHub-hosted; gate on Linux-Runtime so a broken build
|
||
# doesn't burn macOS minutes. MoltenVK/Vulkan path is unique to macOS so per-commit coverage
|
||
# catches regressions per-PR rather than via a stale cron snapshot.
|
||
macOS-Tests-Game:
|
||
needs: [changes, Linux-Runtime]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.runtime == 'true'
|
||
&& needs['Linux-Runtime'].result != 'failure'
|
||
&& needs['Linux-Runtime'].result != 'cancelled'
|
||
&& (github.event_name != 'workflow_dispatch' || inputs.macos)
|
||
uses: ./.github/workflows/test-macos-game.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
# iOS Simulator tests run on macOS runners and take ~24 min, so PRs only trigger them on
|
||
# strictly iOS-specific paths (ios-tests filter); master pushes still run them per-commit.
|
||
iOS-Tests-Game:
|
||
needs: [changes, Linux-Runtime]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.ios-tests == 'true'
|
||
&& needs['Linux-Runtime'].result != 'failure'
|
||
&& needs['Linux-Runtime'].result != 'cancelled'
|
||
&& (github.event_name != 'workflow_dispatch' || inputs.ios)
|
||
uses: ./.github/workflows/test-ios-game.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
# Android tests run on Linux + KVM-accelerated x86_64 emulator. Build APKs on the host,
|
||
# boot the emulator inside reactivecircus/android-emulator-runner, run each suite serially.
|
||
Android-Tests-Game:
|
||
needs: [changes, Linux-Runtime]
|
||
if: |
|
||
!cancelled()
|
||
&& (github.event.pull_request.draft != true || contains(github.event.pull_request.labels.*.name, 'ci-run-on-draft'))
|
||
&& needs.changes.outputs.android == 'true'
|
||
&& needs['Linux-Runtime'].result != 'failure'
|
||
&& needs['Linux-Runtime'].result != 'cancelled'
|
||
&& (github.event_name != 'workflow_dispatch' || inputs.android)
|
||
uses: ./.github/workflows/test-android-game.yml
|
||
with:
|
||
build-type: Debug
|
||
|
||
# Aggregate result for branch protection: mark only "Gate" as required.
|
||
# Skipped jobs (path filters, draft PRs) are fine; failure/cancellation is not.
|
||
# always() on purpose (unlike the !cancelled() test jobs): a cancelled run must
|
||
# report a red Gate, not a skipped (= passing) one.
|
||
Gate:
|
||
needs:
|
||
- changes
|
||
- Assembly-Processor
|
||
- VS-Package
|
||
- iOS-Runtime
|
||
- Android-Runtime
|
||
- Linux-Runtime
|
||
- Windows-Runtime-D3D11
|
||
- Windows-Runtime-D3D12
|
||
- Windows-Runtime-Vulkan
|
||
- Windows-Full
|
||
- Windows-Tests-Game-ApiNeutral
|
||
- Windows-Tests-Simple
|
||
- Windows-Tests-Game-D3D11
|
||
- Windows-Tests-Game-D3D12
|
||
- Windows-Tests-Game-Vulkan
|
||
- Linux-Tests-Simple
|
||
- Linux-Tests-Game
|
||
- macOS-Tests-Game
|
||
- iOS-Tests-Game
|
||
- Android-Tests-Game
|
||
if: always()
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- name: Fail if any needed job failed or was cancelled
|
||
env:
|
||
NEEDS: ${{ toJSON(needs) }}
|
||
run: |
|
||
echo "$NEEDS" | jq -r 'to_entries[] | "\(.value.result)\t\(.key)"'
|
||
test "$(echo "$NEEDS" | jq '[.[] | select(.result=="failure" or .result=="cancelled")] | length')" -eq 0
|