u-analytics 0.4.0

Statistical process control, process capability, Weibull reliability, change-point detection, measurement system analysis (Gage R&R), correlation, regression, distribution analysis, and hypothesis testing.
Documentation
name: NuGet Release

on:
  push:
    branches: [main]
    paths:
      - 'bindings/csharp/UAnalytics/UAnalytics.csproj'
  workflow_dispatch:
    inputs:
      publish:
        description: 'Publish to NuGet.org'
        required: false
        default: true
        type: boolean

env:
  CARGO_TERM_COLOR: always
  CSPROJ_PATH: bindings/csharp/UAnalytics/UAnalytics.csproj
  PACKAGE_NAME: UAnalytics

jobs:
  # ── Check if version changed ──
  check-version:
    name: Check Version
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.read.outputs.version }}
      should_publish: ${{ steps.decide.outputs.should_publish }}
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - name: Read version from csproj
        id: read
        run: |
          VERSION=$(grep -oPm1 '(?<=<Version>)[^<]+' ${{ env.CSPROJ_PATH }})
          echo "version=$VERSION" >> "$GITHUB_OUTPUT"
          echo "Current version: $VERSION"

      - name: Decide whether to publish
        id: decide
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            echo "should_publish=true" >> "$GITHUB_OUTPUT"
            echo "Manual trigger — will publish"
          else
            OLD=$(git show HEAD~1:${{ env.CSPROJ_PATH }} 2>/dev/null | grep -oPm1 '(?<=<Version>)[^<]+' || echo "")
            NEW=$(grep -oPm1 '(?<=<Version>)[^<]+' ${{ env.CSPROJ_PATH }})
            if [ "$OLD" != "$NEW" ]; then
              echo "should_publish=true" >> "$GITHUB_OUTPUT"
              echo "Version changed: $OLD → $NEW"
            else
              echo "should_publish=false" >> "$GITHUB_OUTPUT"
              echo "Version unchanged ($NEW) — skipping"
            fi
          fi

  # ── Build native libraries for each platform ──
  build-native:
    name: Build Native (${{ matrix.rid }})
    needs: check-version
    if: needs.check-version.outputs.should_publish == 'true'
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: true
      matrix:
        include:
          - os: windows-latest
            target: x86_64-pc-windows-msvc
            rid: win-x64
            artifact: u_analytics.dll
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            rid: linux-x64
            artifact: libu_analytics.so
          - os: macos-latest
            target: x86_64-apple-darwin
            rid: osx-x64
            artifact: libu_analytics.dylib
          - os: macos-latest
            target: aarch64-apple-darwin
            rid: osx-arm64
            artifact: libu_analytics.dylib
    steps:
      - uses: actions/checkout@v4

      - name: Checkout path dependencies
        shell: bash
        run: |
          mkdir -p ../../foundation
          git clone --depth 1 https://github.com/iyulab/u-numflow.git ../../foundation/u-numflow

      - uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - uses: Swatinem/rust-cache@v2

      - name: Build release
        run: cargo build --release --features ffi --target ${{ matrix.target }}

      - name: Upload native artifact
        uses: actions/upload-artifact@v4
        with:
          name: native-${{ matrix.rid }}
          path: target/${{ matrix.target }}/release/${{ matrix.artifact }}
          if-no-files-found: error

  # ── Pack & Publish NuGet ──
  pack-and-publish:
    name: Pack & Publish NuGet
    needs: [check-version, build-native]
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '10.0.x'

      - name: Download win-x64 artifact
        uses: actions/download-artifact@v4
        with:
          name: native-win-x64
          path: bindings/csharp/UAnalytics/runtimes/win-x64/native/

      - name: Download linux-x64 artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64
          path: bindings/csharp/UAnalytics/runtimes/linux-x64/native/

      - name: Download osx-x64 artifact
        uses: actions/download-artifact@v4
        with:
          name: native-osx-x64
          path: bindings/csharp/UAnalytics/runtimes/osx-x64/native/

      - name: Download osx-arm64 artifact
        uses: actions/download-artifact@v4
        with:
          name: native-osx-arm64
          path: bindings/csharp/UAnalytics/runtimes/osx-arm64/native/

      - name: Verify native libraries
        run: |
          echo "=== Native libraries ==="
          find bindings/csharp/UAnalytics/runtimes -type f
          echo "=== Sizes ==="
          find bindings/csharp/UAnalytics/runtimes -type f -exec ls -lh {} \;

      - name: Pack NuGet
        run: |
          dotnet pack ${{ env.CSPROJ_PATH }} -c Release -o ./nupkg

      - name: Inspect package
        run: |
          VERSION=${{ needs.check-version.outputs.version }}
          echo "=== Package contents ==="
          unzip -l ./nupkg/${{ env.PACKAGE_NAME }}.${VERSION}.nupkg | grep -E "runtimes|build|lib"

      - name: Upload NuGet package artifact
        uses: actions/upload-artifact@v4
        with:
          name: nuget-package
          path: ./nupkg/*.nupkg

      - name: Publish to NuGet.org
        if: github.event_name == 'push' || inputs.publish != false
        run: |
          VERSION=${{ needs.check-version.outputs.version }}
          dotnet nuget push ./nupkg/${{ env.PACKAGE_NAME }}.${VERSION}.nupkg \
            --api-key ${{ secrets.NUGET_API_KEY }} \
            --source https://api.nuget.org/v3/index.json \
            --skip-duplicate