Add Plugin surface alignment tests #3055
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
| name: build-v2 | |
| # Build & publish wheels for the *v2* Python package living under the | |
| # `python/` directory. These wheels are uploaded to the dedicated | |
| # v2 package index at: | |
| # https://packages.nautechsystems.io/v2/simple/nautilus-trader/ | |
| permissions: | |
| # Principle of least privilege | |
| contents: read | |
| actions: read | |
| on: | |
| push: | |
| branches: | |
| - test-ci | |
| - test-ci-v2 | |
| - develop | |
| - nightly | |
| env: | |
| PACKAGE_DIR: python | |
| jobs: | |
| plan: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| run-tests: ${{ steps.plan.outputs.run_tests }} | |
| run-rust-tests: ${{ steps.plan.outputs.run_rust_tests }} | |
| steps: | |
| # https://github.com/step-security/harden-runner | |
| - uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 | |
| with: | |
| egress-policy: ${{ vars.STEP_SECURITY_EGRESS_POLICY || 'block' }} | |
| allowed-endpoints: >- | |
| ${{ vars.COMMON_ALLOWED_ENDPOINTS }} | |
| ${{ vars.CI_ALLOWED_ENDPOINTS }} | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| fetch-depth: 0 | |
| persist-credentials: false | |
| - name: Plan | |
| id: plan | |
| shell: bash | |
| env: | |
| EVENT_NAME: ${{ github.event_name }} | |
| BASE_SHA: ${{ github.event.pull_request.base.sha }} | |
| BEFORE_SHA: ${{ github.event.before }} | |
| run: bash scripts/ci/plan.sh | |
| pre-commit: | |
| # Fork PRs stay on GitHub-hosted runners. | |
| runs-on: >- | |
| ${{ github.event.pull_request.head.repo.fork | |
| && 'ubuntu-22.04' | |
| || fromJson('["self-hosted", "Linux", "X64", "build-v2"]') }} | |
| env: | |
| # Self-hosted keeps Rust artifacts outside the workspace. | |
| CARGO_TARGET_DIR: >- | |
| ${{ github.event.pull_request.head.repo.fork | |
| && format('{0}/target', github.workspace) | |
| || '/home/runner/.cache/cargo-target/pre-commit' }} | |
| CARGO_CI_PROFILE: >- | |
| ${{ github.event.pull_request.head.repo.fork && 'ci-pr' || 'nextest' }} | |
| # Scopes incremental clippy/doc checks; empty for non-PR/push events. | |
| CHANGED_BASE_SHA: >- | |
| ${{ github.event.pull_request.base.sha || github.event.before }} | |
| steps: | |
| - uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 | |
| with: | |
| egress-policy: ${{ vars.STEP_SECURITY_EGRESS_POLICY || 'block' }} | |
| allowed-endpoints: >- | |
| ${{ vars.COMMON_ALLOWED_ENDPOINTS }} | |
| ${{ vars.CI_ALLOWED_ENDPOINTS }} | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| # Full history so changed-file scripts can resolve CHANGED_BASE_SHA. | |
| fetch-depth: 0 | |
| # Temporary: fail fast on rare runner worktree corruption while we isolate the root cause | |
| - name: Verify immutable CI inputs (post-checkout) | |
| run: bash scripts/ci/verify-ci-inputs.sh post-checkout | |
| - name: Common setup | |
| uses: ./.github/actions/common-setup | |
| with: | |
| python-version: "3.13" | |
| # free-disk-space auto-skips on the nautilus-ci-runner-* pool. | |
| free-disk-space: "true" | |
| build-type: "pre-commit" | |
| rust-cache-enabled: ${{ github.event.pull_request.head.repo.fork && 'true' || 'false' }} | |
| - name: Limit Cargo build jobs on fork PR runners | |
| if: github.event.pull_request.head.repo.fork | |
| run: echo "CARGO_BUILD_JOBS=2" >> "$GITHUB_ENV" | |
| - name: Run pre-commit | |
| run: prek run --all-files | |
| build: | |
| if: needs.plan.outputs.run-tests == 'true' | |
| needs: | |
| - plan | |
| - pre-commit | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| python-version: | |
| - "3.12" | |
| - "3.13" | |
| - "3.14" | |
| runs-on: [self-hosted, Linux, X64, build-v2] | |
| defaults: | |
| run: | |
| shell: bash | |
| env: | |
| BUILD_MODE: release | |
| CARGO_CI_PROFILE: nextest | |
| RUST_BACKTRACE: 1 | |
| # Outside the workspace so it survives actions/checkout's git clean -ffdx, | |
| # giving us persistent on-disk Rust artifact reuse between runs. | |
| CARGO_TARGET_DIR: /home/runner/.cache/cargo-target/py${{ matrix.python-version }} | |
| # yamllint disable rule:line-length | |
| services: | |
| redis: | |
| image: public.ecr.aws/docker/library/redis:7.4.5-alpine3.21@sha256:bb186d083732f669da90be8b0f975a37812b15e913465bb14d845db72a4e3e08 | |
| ports: | |
| - 6379:6379 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| postgres: | |
| image: public.ecr.aws/docker/library/postgres:16.4-alpine@sha256:5660c2cbfea50c7a9127d17dc4e48543eedd3d7a41a595a2dfa572471e37e64c | |
| env: | |
| POSTGRES_USER: postgres | |
| POSTGRES_PASSWORD: pass | |
| POSTGRES_DB: nautilus | |
| ports: | |
| - 5432:5432 | |
| options: >- | |
| --health-cmd "pg_isready -U postgres -d nautilus" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| # yamllint enable rule:line-length | |
| steps: | |
| - uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 | |
| with: | |
| egress-policy: ${{ vars.STEP_SECURITY_EGRESS_POLICY || 'block' }} | |
| allowed-endpoints: >- | |
| ${{ vars.COMMON_ALLOWED_ENDPOINTS }} | |
| ${{ vars.CI_ALLOWED_ENDPOINTS }} | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| # Temporary: fail fast on rare runner worktree corruption while we isolate the root cause | |
| - name: Verify immutable CI inputs (post-checkout) | |
| run: bash scripts/ci/verify-ci-inputs.sh post-checkout | |
| - name: Common setup | |
| uses: ./.github/actions/common-setup | |
| with: | |
| python-version: ${{ matrix.python-version }} | |
| # free-disk-space auto-skips on the nautilus-ci-runner-* pool. | |
| free-disk-space: "true" | |
| # Persistent CARGO_TARGET_DIR replaces Swatinem/rust-cache here. | |
| rust-cache-enabled: "false" | |
| - name: Install Nautilus CLI | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| env: | |
| NAUTILUS_CLI_FORCE_SOURCE: ${{ github.ref == 'refs/heads/nightly' && '1' || '0' }} | |
| run: bash scripts/ci/install-nautilus-cli.sh | |
| - name: Init postgres schema | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| run: nautilus database init --schema ${{ github.workspace }}/schema/sql | |
| env: | |
| POSTGRES_HOST: localhost | |
| POSTGRES_PORT: 5432 | |
| POSTGRES_USERNAME: postgres | |
| POSTGRES_PASSWORD: pass | |
| POSTGRES_DATABASE: nautilus | |
| - name: Cached test data | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| uses: ./.github/actions/common-test-data | |
| - name: Run Rust tests (core) | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| run: make cargo-test-core HYPERSYNC=true NEXTEST_PROFILE=ci | |
| - name: Run Rust tests (adapters) | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| run: make cargo-test-adapters HYPERSYNC=true NEXTEST_PROFILE=ci | |
| - name: Clean Rust test artifacts | |
| if: needs.plan.outputs.run-rust-tests == 'true' | |
| run: | | |
| rm -rf "${CARGO_TARGET_DIR}/nextest" | |
| rm -rf "${CARGO_TARGET_DIR}/${CARGO_CI_PROFILE:-nextest}" | |
| df -h . | |
| # Update version for dev/nightly branches | |
| - name: Update version in pyproject.toml | |
| if: ${{ github.ref != 'refs/heads/master' }} | |
| working-directory: ${{ env.PACKAGE_DIR }} | |
| run: | | |
| bash ../scripts/ci/update-pyproject-version.sh | |
| # Temporary: fail fast on rare runner worktree corruption while we isolate the root cause | |
| - name: Verify immutable CI inputs (pre-wheel build) | |
| run: bash scripts/ci/verify-ci-inputs.sh pre-wheel-build | |
| # Build the wheel for v2 under python/ using maturin | |
| - name: Build wheel (v2) | |
| working-directory: ${{ env.PACKAGE_DIR }} | |
| run: | | |
| MATURIN_VERSION="$(bash ../scripts/tool-version.sh maturin)" | |
| uv run --no-project --no-build --with "maturin==${MATURIN_VERSION}" -- \ | |
| maturin build --release --out ../dist | |
| - name: Run v2 Python tests | |
| working-directory: ${{ env.PACKAGE_DIR }} | |
| run: | | |
| uv sync --group test --no-install-package nautilus-trader | |
| uv pip install "../dist/"*.whl | |
| cd /tmp && uv run --project "$GITHUB_WORKSPACE/${{ env.PACKAGE_DIR }}" --no-sync pytest \ | |
| --import-mode=importlib \ | |
| --rootdir="$GITHUB_WORKSPACE/${{ env.PACKAGE_DIR }}" \ | |
| "$GITHUB_WORKSPACE/${{ env.PACKAGE_DIR }}/tests/" -v | |
| # Temporary: show whether v2 stub or docstring generation dirtied tracked files while we isolate CI drift | |
| - name: Report generated v2 file drift | |
| if: always() | |
| run: | | |
| targets=( | |
| python/generate_docstrings.py | |
| python/generate_stubs.py | |
| crates/pyo3 | |
| ':(glob)python/nautilus_trader/**/*.pyi' | |
| ':(glob)crates/**/src/python/**/*.rs' | |
| ) | |
| changes="$(git status --short --untracked-files=all -- "${targets[@]}")" | |
| if [ -z "$changes" ]; then | |
| echo "No generated v2 file drift detected" | |
| exit 0 | |
| fi | |
| echo "::warning::Tracked or untracked v2 build files changed during the job" | |
| printf '%s\n' "$changes" | |
| echo | |
| git diff --stat HEAD -- "${targets[@]}" || true | |
| - name: Upload wheel artifact | |
| uses: ./.github/actions/upload-artifact-wheel | |
| publish: | |
| needs: | |
| - build | |
| runs-on: ubuntu-latest | |
| # Only publish from mainline branches, never from test branches | |
| if: > | |
| github.ref_name == 'develop' || | |
| github.ref_name == 'nightly' || | |
| github.ref_name == 'master' | |
| environment: r2-${{ github.ref_name }} | |
| permissions: | |
| actions: write # Required for deleting artifacts | |
| contents: read | |
| id-token: write # Required for attestations | |
| attestations: write # Required for attestations | |
| env: | |
| AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} | |
| AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | |
| CLOUDFLARE_R2_URL: ${{ secrets.CLOUDFLARE_R2_URL }} | |
| CLOUDFLARE_R2_REGION: "auto" | |
| CLOUDFLARE_R2_BUCKET_NAME: "packages" | |
| CLOUDFLARE_R2_PREFIX: "v2/simple/nautilus-trader" | |
| steps: | |
| - uses: step-security/harden-runner@a5ad31d6a139d249332a2605b85202e8c0b78450 # v2.19.1 | |
| with: | |
| egress-policy: ${{ vars.STEP_SECURITY_EGRESS_POLICY || 'block' }} | |
| allowed-endpoints: >- | |
| ${{ vars.COMMON_ALLOWED_ENDPOINTS }} | |
| ${{ vars.CI_ALLOWED_ENDPOINTS }} | |
| # Sigstore TUF trust root (for gh attestation verify) | |
| tuf-repo-cdn.sigstore.dev:443 | |
| ${{ secrets.CLOUDFLARE_R2_ALLOWED_HOST }}:443 | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - name: Block develop publish after failed security audit | |
| if: github.ref_name == 'develop' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: bash scripts/ci/check-security-audit-result.sh | |
| - name: Download built wheels | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: dist | |
| pattern: "*.whl" | |
| merge-multiple: true | |
| # https://github.com/actions/attest-build-provenance | |
| - name: Attest wheel provenance | |
| uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 | |
| with: | |
| subject-path: "dist/*.whl" | |
| - name: Verify wheel attestations | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| IDENTITY: ${{ github.server_url }}/${{ github.workflow_ref }} | |
| ISSUER: https://token.actions.githubusercontent.com | |
| run: | | |
| set -e | |
| for whl in dist/*.whl; do | |
| gh attestation verify "$whl" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --cert-identity "$IDENTITY" \ | |
| --cert-oidc-issuer "$ISSUER" | |
| done | |
| - name: Publish wheels to Cloudflare R2 (v2 bucket) | |
| uses: ./.github/actions/publish-wheels | |
| - name: Fetch and delete artifacts for current run | |
| shell: bash | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: |- | |
| bash ./scripts/ci/publish-wheels-delete-artifacts.sh |