perpetual 2.0.0

A self-generalizing gradient boosting machine that doesn't need hyperparameter optimization
Documentation
name: Publish
on:
  release:
    types: [published]
  workflow_dispatch:

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  windows-build:
    strategy:
      matrix:
        pyversion: ["3.10", "3.11", "3.12", "3.13", "3.14"]
    runs-on: "windows-latest"
    steps:
      - uses: actions/checkout@v4
      - name: Install latests stable Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.pyversion }}
          architecture: x64
      - name: Install deps
        run: pip install numpy pandas seaborn scikit-learn toml
      - run: |
          cp README.md package-python/README_PYTHON.md
          cp LICENSE package-python/LICENSE
          cp LICENSE package-r/LICENSE
      - name: Build wheels with maturin
        uses: PyO3/maturin-action@v1
        with:
          target: x86_64
          command: build
          args: --release --strip --interpreter python --manifest-path package-python/Cargo.toml --out dist --sdist
      - name: Save Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-windows-${{ matrix.pyversion }}
          path: dist
          retention-days: 1

  macos-build:
    strategy:
      matrix:
        pyversion: ["3.11", "3.12", "3.13", "3.14"]
        # macos-15-intel: Explicitly targeted as the Intel runner (Free).
        # macos-14: Explicitly targeted as the Apple Silicon runner (Free).
        os: [macos-15-intel, macos-14]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4
      - name: Install latest stable Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.pyversion }}
      - name: Install deps
        run: pip install numpy pandas seaborn scikit-learn toml
      - run: |
          cp README.md package-python/README_PYTHON.md
          cp LICENSE package-python/LICENSE
          cp LICENSE package-r/LICENSE
      - name: Build wheels with maturin
        uses: PyO3/maturin-action@v1
        with:
          command: build
          args: --release --strip --interpreter python --manifest-path package-python/Cargo.toml --out dist --sdist
      - name: Save Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-${{ matrix.os }}-${{ matrix.pyversion }}
          path: dist
          retention-days: 1

  linux-build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        pyversion: ["3.10", "3.11", "3.12", "3.13", "3.14"]
    steps:
      - uses: actions/checkout@v4
      - name: Install latests stable Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.pyversion }}
          architecture: x64
      - name: Install deps
        run: pip install numpy pandas seaborn scikit-learn toml requests
      - run: |
          cp README.md package-python/README_PYTHON.md
          cp LICENSE package-python/LICENSE
          cp LICENSE package-r/LICENSE
      - name: Build wheels with maturin
        uses: PyO3/maturin-action@v1
        with:
          target: x86_64
          manylinux: auto
          command: build
          args: --release --strip --interpreter python${{ matrix.pyversion }} --manifest-path package-python/Cargo.toml --out dist --sdist
      - name: Save Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-linux-${{ matrix.pyversion }}
          path: dist
          retention-days: 1

  linux-arm-build:
    runs-on: ubuntu-24.04-arm
    strategy:
      matrix:
        pyversion: ["3.10", "3.11", "3.12", "3.13", "3.14"]
    steps:
      - uses: actions/checkout@v4
      - name: Install latests stable Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2
      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.pyversion }}
          architecture: arm64
      - name: Install deps
        run: pip install numpy pandas seaborn scikit-learn toml requests
      - run: |
          cp README.md package-python/README_PYTHON.md
          cp LICENSE package-python/LICENSE
          cp LICENSE package-r/LICENSE
      - name: Build wheels with maturin
        uses: PyO3/maturin-action@v1
        with:
          manylinux: auto
          command: build
          args: --release --strip --interpreter python${{ matrix.pyversion }} --manifest-path package-python/Cargo.toml --out dist --sdist
      - name: Save Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: dist-linux-arm-${{ matrix.pyversion }}
          path: dist
          retention-days: 1

  r-release:
    runs-on: ubuntu-22.04
    env:
      GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - uses: r-lib/actions/setup-r@v2
        with:
          r-version: 'release'
          
      - uses: r-lib/actions/setup-pandoc@v2
        
      - name: Install Python Requests
        run: pip install requests

      - uses: r-lib/actions/setup-r-dependencies@v2
        with:
          working-directory: package-r
          use-public-rspm: true
          extra-packages: any::roxygen2
          cache: true

      - name: Prepare R Package Source (No Deps)
        run: python scripts/vendor_r.py --no-deps

      - name: Generate R Documentation
        shell: bash
        run: |
            # Temporarily patch Makevars to allow network build for roxygen2
            if [ -f "package-r/src/Makevars" ]; then
                sed -i "s/ --config 'source.crates-io.replace-with=\"vendored-sources\"' --config 'source.vendored-sources.directory=\"..\/..\/inst\/v\"'//g" package-r/src/Makevars
            fi
            
            # Generate documentation
            Rscript -e 'roxygen2::roxygenise("package-r")'
            
            # Clean up compiled artifacts so they aren't committed to r-universe
            rm -rf package-r/src/rust/target
            rm -f package-r/src/*.o package-r/src/*.so package-r/src/*.dll

      - name: Deploy to R-Universe Branch
        shell: bash
        run: |
          # Configure Git
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          
          # Move package-r content to a temporary location
          mkdir -p ../package_r_temp
          cp -r package-r/* ../package_r_temp/
          cp -r package-r/. ../package_r_temp/ 2>/dev/null || true
          
          # Checkout orphan branch and clean everything
          git checkout --orphan r-universe
          git rm -rf .
          git clean -fdx
          
          # Move content back to root
          cp -r ../package_r_temp/* .
          cp -r ../package_r_temp/. . 2>/dev/null || true
          rm -rf ../package_r_temp

          # Patch Makevars to remove local vendoring and allow network build
          if [ -f "src/Makevars" ]; then
             sed -i "s/ --config 'source.crates-io.replace-with=\"vendored-sources\"' --config 'source.vendored-sources.directory=\"..\/..\/inst\/v\"'//g" src/Makevars
             echo "Patched src/Makevars to allow network build"
          fi
          
          if [ -f "src/Makevars.win" ]; then
             sed -i "s/ --config 'source.crates-io.replace-with=\"vendored-sources\"' --config 'source.vendored-sources.directory=\"..\/..\/inst\/v\"'//g" src/Makevars.win
             echo "Patched src/Makevars.win to allow network build"
          fi

          # Add and Push
          git add .
          git commit -m "chore: vendor source for r-universe build [skip ci]"
          git push -f origin r-universe

  pypi-publish:
    runs-on: ubuntu-latest
    needs: ["windows-build", "macos-build", "linux-build", "linux-arm-build", "r-release"]
    environment:
      name: Test and Deploy
      url: https://pypi.org/p/perpetual
    permissions:
      id-token: write
    steps:
      - name: Retrieve release distributions
        uses: actions/download-artifact@v4
        with:
          pattern: dist-*
          merge-multiple: true
          path: dist
      - name: Publish release distributions to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1

  cargo-publish:
    runs-on: ubuntu-latest
    needs: pypi-publish
    steps:
      - uses: actions/checkout@v4
      - name: Install latest stable Rust
        uses: dtolnay/rust-toolchain@nightly
        with:
          toolchain: nightly
      - uses: Swatinem/rust-cache@v2
      - name: Publish Crate
        run: cargo publish --token ${CRATES_TOKEN} --allow-dirty
        env:
          CRATES_TOKEN: ${{ secrets.CRATES_TOKEN }}