CI #5
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Non-GPU test CI. A `changes` job computes, per suite, whether anything that suite depends on | |
| # changed; each suite job runs only when its filter is true, so untouched packages don't burn | |
| # runner time. `ci-ok` aggregates them into one status (mark it the required check in branch | |
| # protection — a skipped suite counts as success, so required-check gating is not broken). | |
| name: CI | |
| on: | |
| push: | |
| branches: [main] | |
| pull_request: | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| # actions: write is needed because the suite jobs call _test.yml, which runs julia-actions/cache | |
| # (it prunes its own old caches). A called workflow cannot request more than the caller holds, so | |
| # it is granted here at the top level; the `changes` job overrides with a narrower set below. | |
| permissions: | |
| contents: read | |
| actions: write | |
| jobs: | |
| changes: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: read # dorny/paths-filter reads changed files from the PR | |
| outputs: | |
| core: ${{ steps.filter.outputs.core }} | |
| client: ${{ steps.filter.outputs.client }} | |
| gateway: ${{ steps.filter.outputs.gateway }} | |
| server: ${{ steps.filter.outputs.server }} | |
| node: ${{ steps.filter.outputs.node }} | |
| export_lux: ${{ steps.filter.outputs.export_lux }} | |
| export_pytorch: ${{ steps.filter.outputs.export_pytorch }} | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 | |
| id: filter | |
| with: | |
| # `common` (global files + Core) is folded into every suite, since Core is a dependency | |
| # of all of them and the global files affect everything. Each suite then adds its own | |
| # package dir and the vendored lib/* it depends on (submodule bumps show as a change to | |
| # the gitlink path `lib/X.jl`). Filters err toward over-inclusion so a real dependency | |
| # change can never produce a false green. | |
| filters: | | |
| common: &common | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_test.yml' | |
| - 'Project.toml' | |
| - '.gitmodules' | |
| - 'packages/ReactantServerCore/**' | |
| core: | |
| - *common | |
| client: | |
| - *common | |
| - 'packages/ReactantServerClient/**' | |
| - 'lib/gRPCClient.jl' | |
| - 'lib/gRPCClient.jl/**' | |
| gateway: | |
| - *common | |
| - 'packages/ReactantServerGateway/**' | |
| - 'lib/gRPCServer.jl' | |
| - 'lib/gRPCServer.jl/**' | |
| - 'lib/gRPCClient.jl' | |
| - 'lib/gRPCClient.jl/**' | |
| - 'lib/HTTP.jl' | |
| - 'lib/HTTP.jl/**' | |
| - 'lib/Prometheus.jl' | |
| - 'lib/Prometheus.jl/**' | |
| server: | |
| - *common | |
| - 'packages/ReactantServer/**' | |
| - 'lib/Reactant.jl' | |
| - 'lib/Reactant.jl/**' | |
| - 'lib/gRPCServer.jl' | |
| - 'lib/gRPCServer.jl/**' | |
| - 'lib/gRPCClient.jl' # test target only, but the server suite uses it | |
| - 'lib/gRPCClient.jl/**' | |
| - 'lib/HTTP.jl' | |
| - 'lib/HTTP.jl/**' | |
| - 'lib/Prometheus.jl' | |
| - 'lib/Prometheus.jl/**' | |
| node: | |
| - *common | |
| - 'packages/ReactantServerNode/**' | |
| # The Lux round-trip runs whenever anything ReactantServerExport depends on changes. | |
| export_lux: | |
| - *common | |
| - 'packages/ReactantServerExport/**' | |
| - 'packages/ReactantServer/**' | |
| - 'lib/Reactant.jl' | |
| - 'lib/Reactant.jl/**' | |
| - 'lib/gRPCServer.jl' | |
| - 'lib/gRPCServer.jl/**' | |
| - 'lib/HTTP.jl' | |
| - 'lib/HTTP.jl/**' | |
| - 'lib/Prometheus.jl' | |
| - 'lib/Prometheus.jl/**' | |
| # The PyTorch round-trip is heavy (it provisions torch/jax/tensorflow via conda), so it | |
| # runs only when the PyTorch-specific surface changes: the extension, its conda pins, the | |
| # test runner, or the workflow files themselves. It deliberately omits the `common` | |
| # anchor so an unrelated Core/Manifest change does not pay the torch cost. | |
| export_pytorch: | |
| - '.github/workflows/ci.yml' | |
| - '.github/workflows/_test.yml' | |
| - 'packages/ReactantServerExport/ext/PyTorchExportExt.jl' | |
| - 'packages/ReactantServerExport/CondaPkg.toml' | |
| - 'packages/ReactantServerExport/test/runtests.jl' | |
| core: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.core == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServerCore -e 'using Pkg; Pkg.test(; julia_args=[\"--threads=auto,1\"])'" | |
| client: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.client == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServerClient -e 'using Pkg; Pkg.test(; julia_args=[\"--threads=auto,1\"])'" | |
| gateway: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.gateway == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServerGateway -e 'using Pkg; Pkg.test(; julia_args=[\"--threads=auto,1\"])'" | |
| server: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.server == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServer -e 'using Pkg; Pkg.test(; julia_args=[\"--threads=auto,1\"])'" | |
| node: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.node == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServerNode -e 'using Pkg; Pkg.test(; julia_args=[\"--threads=auto,1\"])'" | |
| # Lux-only round-trip: REACTANTSERVER_SKIP_PYTORCH=true keeps runtests.jl from loading PythonCall, | |
| # so no conda env is provisioned and the job stays fast. The standalone test/ project is not a | |
| # Pkg.test target, so it is instantiated explicitly before the runner script. | |
| export-lux: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.export_lux == 'true' }} | |
| uses: ./.github/workflows/_test.yml | |
| with: | |
| command: "julia --color=yes --project=packages/ReactantServerExport/test -e 'using Pkg; Pkg.instantiate()' && REACTANTSERVER_SKIP_PYTORCH=true julia --color=yes --project=packages/ReactantServerExport/test packages/ReactantServerExport/test/runtests.jl" | |
| # Full round-trip including the PyTorch export path. This is a standalone job (not the reusable | |
| # workflow) because it needs an extra cache step for the CondaPkg-provisioned Python environment, | |
| # which julia-actions/cache does not cover. Gated on the narrow export_pytorch filter. | |
| export-pytorch: | |
| needs: changes | |
| if: ${{ needs.changes.outputs.export_pytorch == 'true' }} | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 90 | |
| permissions: | |
| contents: read | |
| actions: write # julia-actions/cache prunes its old caches | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 | |
| with: | |
| submodules: recursive | |
| - uses: julia-actions/setup-julia@fa02766e078afaaf09b14210362cee14137e6a32 # v3.0.2 | |
| with: | |
| version: '1.12' | |
| - uses: julia-actions/cache@a45e8fa8be21c18a06b7177052533149e61e9b38 # v3.1.0 | |
| # Cache the CondaPkg-provisioned Python env (torch/jax/tensorflow); keyed on the conda pins and | |
| # the test Manifest so a torch bump or dep change invalidates it. | |
| - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: packages/ReactantServerExport/test/.CondaPkg | |
| key: condapkg-${{ runner.os }}-${{ hashFiles('packages/ReactantServerExport/CondaPkg.toml', 'packages/ReactantServerExport/test/Project.toml') }} | |
| restore-keys: | | |
| condapkg-${{ runner.os }}- | |
| - name: Run PyTorch export round-trip | |
| run: | | |
| julia --color=yes --project=packages/ReactantServerExport/test -e 'using Pkg; Pkg.instantiate()' | |
| julia --color=yes --project=packages/ReactantServerExport/test packages/ReactantServerExport/test/runtests.jl | |
| ci-ok: | |
| needs: [core, client, gateway, server, node, export-lux, export-pytorch] | |
| if: always() | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Verify no suite failed | |
| run: | | |
| results="${{ join(needs.*.result, ' ') }}" | |
| echo "suite results: $results" | |
| for r in $results; do | |
| if [ "$r" = "failure" ] || [ "$r" = "cancelled" ]; then | |
| echo "A test suite failed or was cancelled." | |
| exit 1 | |
| fi | |
| done | |
| echo "All required suites passed or were skipped." |