Fix SHAPE_PLANE initialization #638
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
| # DO NOT CHANGE ANY SINGLE VERSION. DEPENDABOT HANDLES EVERYTHING. | |
| name: Build Culverin Wheels | |
| on: | |
| push: | |
| branches: [ master ] | |
| tags: [ 'v*' ] | |
| pull_request: | |
| branches: [ master ] | |
| workflow_dispatch: # | |
| jobs: | |
| # build Jolt once per platform | |
| build_jolt: | |
| name: Build Jolt (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [windows-latest, ubuntu-latest, macos-latest] | |
| outputs: | |
| jolt-hash: ${{ steps.jolt_hash.outputs.hash }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Get submodule hash | |
| id: jolt_hash | |
| shell: bash | |
| run: echo "hash=$(git rev-parse HEAD:extern/JoltPhysics)" >> $GITHUB_OUTPUT | |
| - name: Cache Jolt static lib | |
| id: cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: jolt-install | |
| key: jolt-${{ matrix.os }}-${{ steps.jolt_hash.outputs.hash }}-v12 | |
| - name: Install deps (Linux) | |
| if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Linux' | |
| run: sudo apt-get install -y clang lld ninja-build | |
| - name: Install LLVM (macOS) | |
| if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'macOS' | |
| run: brew install llvm ninja | |
| - name: Install ninja (Windows) | |
| if: steps.cache.outputs.cache-hit != 'true' && runner.os == 'Windows' | |
| run: choco install ninja | |
| - name: Build Jolt | |
| if: steps.cache.outputs.cache-hit != 'true' | |
| shell: bash | |
| run: | | |
| # 1. Physically patch Jolt's hardcoded flags out of existence | |
| python - << 'EOF' | |
| import os | |
| path = 'extern/JoltPhysics/Build/CMakeLists.txt' | |
| with open(path, 'r') as f: text = f.read() | |
| # Force RTTI enabled natively | |
| text = text.replace('-fno-rtti', '-frtti') | |
| text = text.replace('/GR-', '/GR') | |
| # Force MSVC Dynamic Runtime (DLL) | |
| text = text.replace('MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>"', 'MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>DLL"') | |
| with open(path, 'w') as f: f.write(text) | |
| EOF | |
| # 2. Configure CMake normally | |
| COMMON_CMAKE_ARGS=( | |
| "-G" "Ninja" | |
| "-DCMAKE_BUILD_TYPE=Release" | |
| "-DDOUBLE_PRECISION=ON" | |
| "-DDEBUG_RENDERER_IN_DEBUG_AND_RELEASE=ON" | |
| "-DCMAKE_CXX_STANDARD=23" | |
| "-DCMAKE_INSTALL_PREFIX=$PWD/jolt-install" | |
| "-DBUILD_SHARED_LIBS=OFF" | |
| "-DTARGET_UNIT_TESTS=OFF" | |
| "-DTARGET_PERFORMANCE_TEST=OFF" | |
| "-DTARGET_SAMPLES=OFF" | |
| "-DTARGET_VIEWER=OFF" | |
| ) | |
| if [ "$RUNNER_OS" == "Windows" ]; then | |
| cmake -S extern/JoltPhysics/Build -B jolt-build \ | |
| "${COMMON_CMAKE_ARGS[@]}" \ | |
| -DCMAKE_C_COMPILER="clang-cl" \ | |
| -DCMAKE_CXX_COMPILER="clang-cl" \ | |
| -DCMAKE_CXX_FLAGS="/arch:AVX2 /fp:fast -DJPH_OBJECT_LAYER_BITS=32" | |
| elif [ "$RUNNER_OS" == "macOS" ]; then | |
| export MACOSX_DEPLOYMENT_TARGET=13.3 | |
| cmake -S extern/JoltPhysics/Build -B jolt-build \ | |
| "${COMMON_CMAKE_ARGS[@]}" \ | |
| -DCMAKE_C_COMPILER="/opt/homebrew/opt/llvm/bin/clang" \ | |
| -DCMAKE_CXX_COMPILER="/opt/homebrew/opt/llvm/bin/clang++" \ | |
| -DCMAKE_CXX_FLAGS="-mcpu=apple-m1 -mmacosx-version-min=13.0 -DJPH_OBJECT_LAYER_BITS=32" | |
| else | |
| cmake -S extern/JoltPhysics/Build -B jolt-build \ | |
| "${COMMON_CMAKE_ARGS[@]}" \ | |
| -DCMAKE_C_COMPILER="clang" \ | |
| -DCMAKE_CXX_COMPILER="clang++" \ | |
| -DCMAKE_C_FLAGS="-fPIC" \ | |
| -DCMAKE_CXX_FLAGS="-march=x86-64-v3 -ffast-math -fomit-frame-pointer -fPIC -DJPH_OBJECT_LAYER_BITS=32" | |
| fi | |
| cmake --build jolt-build --parallel | |
| cmake --install jolt-build | |
| - name: Upload Jolt artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: jolt-prebuilt-${{ matrix.os }} | |
| path: jolt-install/ | |
| retention-days: 3 | |
| # =========================================================================== | |
| # JOB 1: PRODUCTION RELEASE (Clean Binaries) | |
| # =========================================================================== | |
| build_wheels: | |
| name: Release Build (${{ matrix.os }}) | |
| needs: [build_jolt] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [windows-latest, ubuntu-latest, macos-latest] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| enable-cache: true | |
| - name: Install LLVM (macOS) | |
| if: runner.os == 'macOS' | |
| run: brew install llvm | |
| - name: Download prebuilt Jolt | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: jolt-prebuilt-${{ matrix.os }} | |
| path: jolt-install | |
| - name: Set Jolt CMake dir | |
| shell: bash | |
| run: echo "JOLT_CMAKE_DIR=$(pwd)/jolt-install/lib/cmake/Jolt" >> $GITHUB_ENV | |
| - name: Set Jolt CMake dir (Windows override) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| $dir = (Resolve-Path "jolt-install/lib/cmake/Jolt").Path.Replace('\', '/') | |
| echo "JOLT_CMAKE_DIR=$dir" >> $env:GITHUB_ENV | |
| - name: Build Wheels | |
| uses: pypa/cibuildwheel@v3.4.1 | |
| env: | |
| CIBW_SKIP: "*-musllinux_* *-win32 *_i686" | |
| CIBW_BUILD: "cp312-* cp313-* cp313t-* cp314-* cp314t-*" | |
| CIBW_ENABLE: "cpython-freethreading" | |
| CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 | |
| CIBW_MANYLINUX_AARCH64_IMAGE: manylinux_2_28 | |
| CIBW_BUILD_FRONTEND: "uv" | |
| CIBW_ENVIRONMENT_PASS: JOLT_CMAKE_DIR | |
| CIBW_ENVIRONMENT_LINUX: > | |
| CC=clang | |
| CXX=clang++ | |
| CMAKE_GENERATOR=Ninja | |
| CMAKE_ARGS="-DENABLE_SANITIZER=OFF -DCMAKE_BUILD_TYPE=Release -DDOUBLE_PRECISION=ON -DJOLT_PREBUILT_DIR=/project/jolt-install/lib/cmake/Jolt" | |
| CIBW_ENVIRONMENT_MACOS: > | |
| CC=/opt/homebrew/opt/llvm/bin/clang | |
| CXX=/opt/homebrew/opt/llvm/bin/clang++ | |
| CMAKE_GENERATOR=Ninja MACOSX_DEPLOYMENT_TARGET=13.3 | |
| CMAKE_ARGS="-DENABLE_SANITIZER=OFF -DCMAKE_BUILD_TYPE=Release -DDOUBLE_PRECISION=ON -DJOLT_PREBUILT_DIR=$JOLT_CMAKE_DIR" | |
| CIBW_ENVIRONMENT_WINDOWS: > | |
| CC=clang-cl | |
| CXX=clang-cl | |
| CMAKE_GENERATOR=Ninja | |
| CMAKE_ARGS="-DENABLE_SANITIZER=OFF -DCMAKE_BUILD_TYPE=Release -DDOUBLE_PRECISION=ON -DJOLT_PREBUILT_DIR=$JOLT_CMAKE_DIR" | |
| CIBW_BEFORE_ALL_LINUX: > | |
| (dnf install -y clang llvm || yum install -y clang llvm || apk add --no-cache clang llvm-dev) && | |
| pip install ninja | |
| CIBW_TEST_REQUIRES: numpy psutil pytest | |
| CIBW_TEST_COMMAND: | | |
| pytest {project}/tests/ | |
| echo "All tests completed!" | |
| - name: Build Experimental Wheels (3.15) | |
| shell: bash | |
| run: | | |
| # 1. Setup Platform-Specific Compilers to match Jolt Build | |
| if [[ "${{ runner.os }}" == "Linux" ]]; then | |
| echo "Configuring LLVM 22 for Linux..." | |
| wget https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| sudo ./llvm.sh 22 | |
| export CC=clang-22 | |
| export CXX=clang++-22 | |
| export LDFLAGS="-fuse-ld=lld-22" | |
| elif [[ "${{ runner.os }}" == "macOS" ]]; then | |
| echo "Configuring Homebrew LLVM for macOS..." | |
| # Match the paths used in the build_jolt job exactly | |
| export CC="/opt/homebrew/opt/llvm/bin/clang" | |
| export CXX="/opt/homebrew/opt/llvm/bin/clang++" | |
| export LDFLAGS="-L/opt/homebrew/opt/llvm/lib" | |
| export CPPFLAGS="-I/opt/homebrew/opt/llvm/include" | |
| export PATH="/opt/homebrew/opt/llvm/bin:$PATH" | |
| else | |
| echo "Configuring clang-cl for Windows..." | |
| export CC=clang-cl | |
| export CXX=clang-cl | |
| fi | |
| # 2. Install the alpha versions | |
| uv python install 3.15 3.15t | |
| # 3. Build Arguments (Using the Jolt Cache) | |
| # We use the $JOLT_CMAKE_DIR established in the "Set Jolt CMake dir" step | |
| CMAKE_FLAGS="-GNinja;-DENABLE_SANITIZER=OFF;-DCMAKE_BUILD_TYPE=Release;-DDOUBLE_PRECISION=ON;-DJOLT_PREBUILT_DIR=${JOLT_CMAKE_DIR}" | |
| CXX_FLAGS="-Wno-overriding-option" | |
| # 4. Build Standard 3.15 | |
| uv build --wheel --python 3.15 --out-dir wheelhouse/ \ | |
| --config-setting=cmake.args="$CMAKE_FLAGS" \ | |
| --config-setting=cmake.define.CMAKE_CXX_FLAGS="$CXX_FLAGS" | |
| # 5. Build Free-Threaded 3.15t | |
| uv build --wheel --python 3.15t --out-dir wheelhouse/ \ | |
| --config-setting=cmake.args="$CMAKE_FLAGS" \ | |
| --config-setting=cmake.define.CMAKE_CXX_FLAGS="$CXX_FLAGS" | |
| # 6. Repair and Tag Linux Wheels for PyPI | |
| if [[ "${{ runner.os }}" == "Linux" ]]; then | |
| echo "Installing patchelf for auditwheel..." | |
| sudo apt-get update -y && sudo apt-get install -y patchelf | |
| echo "Repairing Linux wheels..." | |
| mkdir -p wheelhouse/repaired | |
| # Find only the newly built linux wheels | |
| for whl in wheelhouse/*linux_x86_64.whl; do | |
| if [ -f "$whl" ]; then | |
| echo "Repairing $whl..." | |
| # Use --plat auto to avoid string mismatch errors | |
| uvx auditwheel repair "$whl" --plat auto -w wheelhouse/repaired/ | |
| fi | |
| done | |
| # Replace raw linux_x86_64 wheels with manylinux compliant ones | |
| if [ "$(ls -A wheelhouse/repaired/)" ]; then | |
| rm wheelhouse/*linux_x86_64.whl | |
| mv wheelhouse/repaired/*.whl wheelhouse/ | |
| fi | |
| rmdir wheelhouse/repaired/ | |
| fi | |
| - name: Upload Artifacts | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: culverin-release-${{ matrix.os }} | |
| path: ./wheelhouse/*.whl | |
| # =========================================================================== | |
| # JOB 2 & 3: SANITIZER VALIDATION (ASan/UBSan/TSan Check) | |
| # =========================================================================== | |
| check_sanitizers: | |
| name: Sanitizer Validation (Ubuntu) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install LLVM 22 | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y wget lsb-release software-properties-common gnupg | |
| wget https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| sudo ./llvm.sh 22 | |
| # Ensure the specific sanitizer runtimes are present | |
| sudo apt-get install -y clang-22 lld-22 libclang-rt-22-dev ninja-build | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Build Wheels with Sanitizers | |
| run: | | |
| export CC=clang-22 | |
| export CXX=clang++-22 | |
| export CFLAGS="-fno-sanitize=alignment" | |
| export CXXFLAGS="-fno-sanitize=alignment" | |
| export LDFLAGS="-fuse-ld=lld-22" | |
| # Force uv to use Python 3.14 | |
| uv build --wheel --python 3.14 \ | |
| --config-setting=cmake.args="-DENABLE_SANITIZER=ON;-DCMAKE_BUILD_TYPE=RelWithDebInfo;-DDOUBLE_PRECISION=ON" | |
| - name: Install and Test | |
| run: | | |
| uv venv --python 3.14 | |
| # Install the wheel AND the test dependencies | |
| uv pip install dist/*.whl numpy psutil pytest | |
| ASAN_RT=$(find /usr/lib/llvm-22 -name "libclang_rt.asan-x86_64.so" | head -n 1) | |
| echo "ASan Runtime: ${ASAN_RT}" | |
| export ASAN_OPTIONS="detect_leaks=0:detect_odr_violation=0:halt_on_error=1" | |
| export UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=1" | |
| if [ -n "$ASAN_RT" ]; then export LD_PRELOAD="$ASAN_RT"; fi | |
| # Use --no-project so it doesn't try to re-build that editable install | |
| uv run --no-project tests/test_core.py | |
| uv run --no-project tests/benchmark.py --leak | |
| # Thread sanitizer | |
| linux_tsan: | |
| name: TSan (${{ matrix.python-version }}${{ matrix.gil_flag }}) | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Testing the full spectrum: | |
| # 3.12 (Legacy GIL), 3.13t (Current Stable Free-Threaded), 3.14t (Bleeding Edge) | |
| python-version: ["3.12", "3.13", "3.14"] | |
| include: | |
| - python-version: "3.12" | |
| gil_flag: "" # Standard GIL only | |
| - python-version: "3.13" | |
| gil_flag: "t" # Free-threaded | |
| - python-version: "3.14" | |
| gil_flag: "t" # Experimental Free-threaded | |
| - python-version: "3.15" | |
| gil_flag: "t" # The subject to test with! | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install LLVM 22 | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y wget lsb-release software-properties-common gnupg | |
| wget https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| sudo ./llvm.sh 22 | |
| - uses: astral-sh/setup-uv@v7 | |
| with: | |
| # Dynamically resolve version (e.g., 3.14t) | |
| python-version: "${{ matrix.python-version }}${{ matrix.gil_flag }}" | |
| - name: Build and Scan with TSan | |
| env: | |
| CC: "/usr/bin/clang-22" | |
| CXX: "/usr/bin/clang++-22" | |
| # -O1 is the TSan sweet spot: enough optimization to be fast, | |
| # but keeps the stack traces readable. | |
| CFLAGS: "-fsanitize=thread -g -O1 -fno-omit-frame-pointer" | |
| CXXFLAGS: "-fsanitize=thread -g -O1 -fno-omit-frame-pointer -DENABLE_SANITIZER -D__SANITIZE_THREAD__" | |
| LDFLAGS: "-fsanitize=thread" | |
| CMAKE_ARGS: "-DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_STANDARD=23 -DENABLE_THREAD_SANITIZER=ON" | |
| PYTEST_ADDOPTS: "-s" | |
| run: | | |
| # Use uv to handle the venv creation for the specific matrix version | |
| uv venv --python "${{ matrix.python-version }}${{ matrix.gil_flag }}" --clear | |
| # Install deps into the version-specific venv | |
| uv pip install scikit-build-core numpy psutil pytest | |
| uv pip install -e . --no-build-isolation | |
| # Locate the specific TSan runtime for LLVM 22 | |
| export TSAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-22 | |
| TSAN_LIB=$(find /usr/lib/llvm-22 -name "libclang_rt.tsan-x86_64.so" | head -n 1) | |
| # Execution environment | |
| export LD_PRELOAD=$TSAN_LIB | |
| export TSAN_OPTIONS="suppressions=${{ github.workspace }}/tsan.supp second_deadlock_stack=1 halt_on_error=1 symbolize=1" | |
| # Run stress benchmark followed by unit tests | |
| source .venv/bin/activate | |
| python tests/benchmark.py --stress | |
| python -m pytest tests/test_core.py | |
| # =========================================================================== | |
| # JOB 3.2: GCC DEEP VALIDATION (Full Source Build) | |
| # =========================================================================== | |
| linux_gcc_validation: | |
| name: GCC 14 Deep Validation (Ubuntu) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Install GCC 14 and Ninja | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-14 g++-14 lld ninja-build | |
| # Set GCC 14 as the default system compiler | |
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-14 100 | |
| sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-14 100 | |
| - name: Patch Jolt Source (Force RTTI) | |
| shell: bash | |
| run: | | |
| python3 - << 'EOF' | |
| import os | |
| path = 'extern/JoltPhysics/Build/CMakeLists.txt' | |
| if os.path.exists(path): | |
| with open(path, 'r') as f: text = f.read() | |
| text = text.replace('-fno-rtti', '-frtti') | |
| text = text.replace('/GR-', '/GR') | |
| with open(path, 'w') as f: f.write(text) | |
| print("Jolt patched successfully.") | |
| EOF | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Deep Build with GCC (Jolt + Extension) | |
| env: | |
| CC: gcc | |
| CXX: g++ | |
| # Use LLD for speed, but now it's linking GCC objects against GCC objects | |
| LDFLAGS: "-fuse-ld=lld" | |
| # NOTE: JOLT_PREBUILT_DIR is NOT defined. | |
| # This triggers 'add_subdirectory' in your CMakeLists.txt | |
| CMAKE_ARGS: >- | |
| -DENABLE_SANITIZER=OFF | |
| -DCMAKE_BUILD_TYPE=Release | |
| -DDOUBLE_PRECISION=ON | |
| -DJPH_OBJECT_LAYER_BITS=32 | |
| run: | | |
| # Build using 3.14t to ensure thread-safety and C23 compliance | |
| uv build --wheel --python 3.14t --out-dir dist/ \ | |
| --config-setting=cmake.define.CMAKE_C_COMPILER=gcc \ | |
| --config-setting=cmake.define.CMAKE_CXX_COMPILER=g++ \ | |
| --config-setting=cmake.verbose=true | |
| - name: Smoke Test GCC Wheel | |
| run: | | |
| # 1. Setup environment | |
| uv venv --python 3.14t | |
| # 2. Force install ONLY the wheel we built, plus dependencies | |
| # --no-index ensures it doesn't try to look at the local source folder | |
| uv pip install dist/*.whl numpy | |
| # 3. CRITICAL: Move to a directory that has NO pyproject.toml or src/ | |
| # This ensures 'import culverin' loads from site-packages, not the current folder. | |
| mkdir test_jail | |
| cd test_jail | |
| # 4. Run tests using 'uv run --no-project' | |
| VERSION_INFO=$(uv run --no-project python -c "import culverin; print(culverin.__version__)") | |
| echo "Built version: $VERSION_INFO" | |
| if [[ "$VERSION_INFO" != *"GCC"* ]]; then | |
| echo "Error: Metadata check failed. Expected GCC in version string." | |
| exit 1 | |
| fi | |
| uv run --no-project python -c "import culverin; w=culverin.PhysicsWorld(); print('World created safely')" | |
| # =========================================================================== | |
| # JOB 3.5: SANITY CHECKS | |
| # =========================================================================== | |
| pre_flight_sanity_check: | |
| name: Final Artifact Validation | |
| needs: [build_wheels] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: "Checkout code with Full History & Tags" | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| fetch-tags: true # Ensure we can verify tag reachability | |
| - name: "Download All Built Wheels" | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| pattern: culverin-release-* | |
| merge-multiple: true | |
| - name: "1. Check for Leaked Debug Symbols (.pdb)" | |
| shell: bash | |
| run: | | |
| echo "Searching for hidden .pdb files in wheels..." | |
| for wheel in dist/*.whl; do | |
| if unzip -l "$wheel" | grep -iq "\.pdb$"; then | |
| echo "::error::Found .pdb in $wheel! Check your scikit-build-core excludes." | |
| exit 1 | |
| fi | |
| done | |
| - name: "2. Verify Wheel Count (Expected: 21)" | |
| shell: bash | |
| run: | | |
| # More robust file counting using find | |
| EXPECTED=21 | |
| ACTUAL=$(find dist -name '*.whl' | wc -l) | |
| if [ "$ACTUAL" -ne "$EXPECTED" ]; then | |
| echo "::error::Wheel count mismatch! Expected $EXPECTED, found $ACTUAL." | |
| find dist -name '*.whl' | |
| exit 1 | |
| fi | |
| - name: "3. Robust Version Sync (tomllib)" | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| shell: bash | |
| run: | | |
| # Use Python's native tomllib to avoid grep fragility | |
| PY_VER=$(python3 -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])") | |
| TAG_VER=${GITHUB_REF_NAME#v} | |
| echo "Tag: $TAG_VER, pyproject.toml: $PY_VER" | |
| if [ "$TAG_VER" != "$PY_VER" ]; then | |
| echo "::error::Metadata Mismatch: Tag ($TAG_VER) != pyproject.toml ($PY_VER)" | |
| exit 1 | |
| fi | |
| - name: "4. Branch Reachability Check" | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| run: | | |
| # Verify the tag exists on the master branch history | |
| if ! git branch -r --contains ${{ github.ref }} | grep -q "origin/master"; then | |
| echo "::error::The tag ${{ github.ref_name }} is not reachable from origin/master." | |
| echo "Aborting: You are trying to release a commit that isn't on the main line." | |
| exit 1 | |
| fi | |
| # =========================================================================== | |
| # JOB 4: PERFORMANCE REGRESSION | |
| # =========================================================================== | |
| performance_regression: | |
| name: Performance Regression Benchmarks | |
| needs: [build_wheels] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| submodules: recursive | |
| - name: Set up uv | |
| uses: astral-sh/setup-uv@v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.13' | |
| - name: Download Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| pattern: culverin-release-ubuntu-latest | |
| path: dist | |
| merge-multiple: true | |
| - name: Install dependencies and Pre-built Wheel | |
| run: | | |
| uv pip install --system numpy psutil | |
| WHEEL=$(ls dist/culverin-*cp313-cp313-manylinux*.whl | head -n 1) | |
| uv pip install --system "$WHEEL" | |
| - name: CPU Feature Audit | |
| run: | | |
| echo "### Runner CPU Info" >> $GITHUB_STEP_SUMMARY | |
| # Check for v3 requirements (AVX2, BMI2, FMA) | |
| grep -E "avx2|bmi2|fma" /proc/cpuinfo > /dev/null \ | |
| && echo "✅ Hardware supports x86-64-v3" >> $GITHUB_STEP_SUMMARY \ | |
| || echo "❌ ERROR: Ancient CPU detected (Missing v3 features)" >> $GITHUB_STEP_SUMMARY | |
| # List all flags for deep dive | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| lscpu >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| - name: Run Performance Suite | |
| shell: bash | |
| run: | | |
| echo "## Performance Benchmark Results" >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| # Fix: Explicitly point to the tests/ directory | |
| echo "Running test_perf.py..." | |
| python tests/test_perf.py >> $GITHUB_STEP_SUMMARY | |
| echo -e "\nRunning benchmark.py..." | |
| python tests/benchmark.py --leak >> $GITHUB_STEP_SUMMARY | |
| python tests/benchmark.py --churn >> $GITHUB_STEP_SUMMARY | |
| echo '```' >> $GITHUB_STEP_SUMMARY | |
| continue-on-error: false | |
| # =========================================================================== | |
| # JOB 5: PUBLISH | |
| # =========================================================================== | |
| github-release: | |
| name: Create GitHub Release | |
| needs: [build_wheels, check_sanitizers, linux_tsan, pre_flight_sanity_check, performance_regression] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Download Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: wheelhouse | |
| pattern: culverin-release-* | |
| merge-multiple: true | |
| - name: Upload to GitHub Release | |
| uses: softprops/action-gh-release@v3 | |
| with: | |
| files: wheelhouse/*.whl | |
| body: | | |
| Culverin Physics Release ${{ github.ref_name }} | |
| Standard Release Binaries (Sanitizer validated) | |
| prerelease: true | |
| pypi-publish: | |
| name: Upload to PyPI | |
| needs: [build_wheels, check_sanitizers, linux_tsan, pre_flight_sanity_check, performance_regression] | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| runs-on: ubuntu-latest | |
| environment: pypi | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download Artifacts | |
| uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| pattern: culverin-release-* | |
| merge-multiple: true | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| packages-dir: dist/ | |
| skip-existing: true | |