test sfor CI #32
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 and Release | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| jobs: | |
| dotnet-build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: 9.0.x | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build managed projects | |
| run: dotnet build --configuration Release --no-restore | |
| native-linux: | |
| needs: dotnet-build | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install build dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y build-essential cmake libopenblas-dev liblapack-dev liblapacke-dev | |
| - name: Configure native build | |
| run: cmake -S native -B native/build/linux -DCMAKE_BUILD_TYPE=Release | |
| - name: Build native library | |
| run: cmake --build native/build/linux --target mlxsharp --config Release | |
| - name: Package native artifact | |
| run: | | |
| mkdir -p artifacts/native/linux-x64 | |
| cp native/build/linux/libmlxsharp.so artifacts/native/linux-x64/ | |
| - name: Upload native artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-linux-x64 | |
| path: artifacts/native/linux-x64/libmlxsharp.so | |
| native-macos: | |
| needs: dotnet-build | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install CMake | |
| run: brew install cmake | |
| - name: Configure native build | |
| run: cmake -S native -B native/build/macos -DCMAKE_BUILD_TYPE=Release | |
| - name: Build native library | |
| run: cmake --build native/build/macos --target mlxsharp --config Release | |
| - name: Package native artifact | |
| run: | | |
| mkdir -p artifacts/native/osx-arm64 | |
| cp native/build/macos/libmlxsharp.dylib artifacts/native/osx-arm64/ | |
| - name: Upload native artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-osx-arm64 | |
| path: artifacts/native/osx-arm64/libmlxsharp.dylib | |
| package-test: | |
| needs: | |
| - native-linux | |
| - native-macos | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup .NET | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: 9.0.x | |
| - name: Show .NET info | |
| run: dotnet --info | |
| - name: Restore dependencies | |
| run: dotnet restore | |
| - name: Build C# projects (initial validation) | |
| run: dotnet build --configuration Release --no-restore | |
| - name: Setup Python for HuggingFace | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install HuggingFace CLI | |
| run: pip install huggingface_hub | |
| - name: Download test model from HuggingFace | |
| run: | | |
| mkdir -p models | |
| huggingface-cli download mlx-community/Qwen1.5-0.5B-Chat-4bit --local-dir models/Qwen1.5-0.5B-Chat-4bit | |
| echo "Model files:" | |
| ls -la models/Qwen1.5-0.5B-Chat-4bit/ | |
| - name: Download macOS native library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: native-osx-arm64 | |
| path: artifacts/native/osx-arm64 | |
| - name: Download Linux native library | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: native-linux-x64 | |
| path: artifacts/native/linux-x64 | |
| - name: Stage native libraries in project | |
| run: | | |
| mkdir -p src/MLXSharp/runtimes/osx-arm64/native | |
| cp artifacts/native/osx-arm64/libmlxsharp.dylib src/MLXSharp/runtimes/osx-arm64/native/ | |
| mkdir -p src/MLXSharp/runtimes/linux-x64/native | |
| cp artifacts/native/linux-x64/libmlxsharp.so src/MLXSharp/runtimes/linux-x64/native/ | |
| - name: Build C# projects with native libraries | |
| run: dotnet build --configuration Release --no-restore | |
| - name: Copy native library to test output | |
| run: | | |
| TEST_OUTPUT="src/MLXSharp.Tests/bin/Release/net9.0" | |
| mkdir -p "$TEST_OUTPUT/runtimes/osx-arm64/native" | |
| cp src/MLXSharp/runtimes/osx-arm64/native/libmlxsharp.dylib "$TEST_OUTPUT/runtimes/osx-arm64/native/" | |
| ls -la "$TEST_OUTPUT/runtimes/osx-arm64/native/" | |
| - name: Run tests | |
| run: | | |
| dotnet test \ | |
| --configuration Release \ | |
| --no-build \ | |
| --logger "trx;LogFileName=TestResults.trx" \ | |
| --logger "console;verbosity=detailed" \ | |
| --results-directory artifacts/test-results | |
| env: | |
| MLXSHARP_MODEL_PATH: ${{ github.workspace }}/models/Qwen1.5-0.5B-Chat-4bit | |
| - name: Prepare artifact folders | |
| run: | | |
| mkdir -p artifacts/test-results | |
| mkdir -p artifacts/packages | |
| mkdir -p artifacts/native | |
| cp artifacts/native/osx-arm64/libmlxsharp.dylib artifacts/native/ | |
| cp artifacts/native/linux-x64/libmlxsharp.so artifacts/native/ | |
| - name: Pack MLXSharp library | |
| run: dotnet pack src/MLXSharp/MLXSharp.csproj --configuration Release --output artifacts/packages -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/artifacts/native/osx-arm64/libmlxsharp.dylib -p:MLXSharpLinuxNativeBinary=$GITHUB_WORKSPACE/artifacts/native/linux-x64/libmlxsharp.so | |
| - name: Pack MLXSharp.SemanticKernel library | |
| run: dotnet pack src/MLXSharp.SemanticKernel/MLXSharp.SemanticKernel.csproj --configuration Release --output artifacts/packages -p:MLXSharpMacNativeBinary=$GITHUB_WORKSPACE/artifacts/native/osx-arm64/libmlxsharp.dylib -p:MLXSharpLinuxNativeBinary=$GITHUB_WORKSPACE/artifacts/native/linux-x64/libmlxsharp.so -p:MLXSharpSkipLinuxNativeValidation=true | |
| - name: Verify package contains native libraries | |
| run: | | |
| echo "Checking package contents..." | |
| shopt -s nullglob | |
| packages=(artifacts/packages/*.nupkg) | |
| if [ ${#packages[@]} -eq 0 ]; then | |
| echo "✗ ERROR: No packages were produced" | |
| exit 1 | |
| fi | |
| missing=0 | |
| for package in "${packages[@]}"; do | |
| echo "Inspecting ${package}" | |
| filename=$(basename "${package}") | |
| case "${filename}" in | |
| MLXSharp.SemanticKernel.*.nupkg) | |
| echo " ↷ Skipping native check for ${filename}" | |
| ;; | |
| MLXSharp.*.nupkg) | |
| package_missing=0 | |
| if unzip -l "${package}" | grep -q "runtimes/osx-arm64/native/libmlxsharp.dylib"; then | |
| echo " ✓ macOS library present" | |
| else | |
| echo " ✗ macOS library missing" | |
| package_missing=1 | |
| fi | |
| if unzip -l "${package}" | grep -q "runtimes/linux-x64/native/libmlxsharp.so"; then | |
| echo " ✓ Linux library present" | |
| else | |
| echo " ✗ Linux library missing" | |
| package_missing=1 | |
| fi | |
| if [ ${package_missing} -ne 0 ]; then | |
| unzip -l "${package}" | |
| missing=1 | |
| fi | |
| ;; | |
| *) | |
| echo " ↷ Skipping native check for ${filename}" | |
| ;; | |
| esac | |
| done | |
| if [ $missing -ne 0 ]; then | |
| exit 1 | |
| fi | |
| - name: Upload native artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-libs | |
| path: artifacts/native | |
| - name: Upload packages artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: packages | |
| path: artifacts/packages | |
| - name: Upload test results | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: test-results | |
| path: artifacts/test-results | |
| - name: Publish test results | |
| if: always() | |
| uses: actions/upload-test-results@v1 | |
| with: | |
| test-results: artifacts/test-results/TestResults.trx | |
| check-name: dotnet tests | |
| release: | |
| if: github.ref == 'refs/heads/main' && github.event_name == 'push' | |
| needs: package-test | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: recursive | |
| - name: Determine MLX version | |
| id: mlx_version | |
| run: | | |
| git submodule update --init --recursive | |
| git -C extern/mlx fetch --tags | |
| if MLX_TAG=$(git -C extern/mlx describe --tags --abbrev=0 2>/dev/null); then | |
| echo "Detected MLX tag: ${MLX_TAG}" | |
| else | |
| echo "::warning::Unable to determine MLX tag; falling back to commit hash" | |
| MLX_TAG="unknown" | |
| fi | |
| MLX_COMMIT=$(git -C extern/mlx rev-parse --short HEAD) | |
| echo "tag=${MLX_TAG}" >> "$GITHUB_OUTPUT" | |
| echo "commit=${MLX_COMMIT}" >> "$GITHUB_OUTPUT" | |
| - name: Extract version from Directory.Build.props | |
| id: version | |
| run: | | |
| VERSION=$(grep -oP '<Version>\K[^<]+' Directory.Build.props) | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "Extracted version: $VERSION" | |
| - name: Check if tag exists | |
| id: check_tag | |
| run: | | |
| if git ls-remote --tags origin | grep -q "refs/tags/v${{ steps.version.outputs.version }}"; then | |
| echo "exists=true" >> $GITHUB_OUTPUT | |
| echo "Tag v${{ steps.version.outputs.version }} already exists" | |
| else | |
| echo "exists=false" >> $GITHUB_OUTPUT | |
| echo "Tag v${{ steps.version.outputs.version }} does not exist" | |
| fi | |
| - name: Download package artifacts | |
| if: steps.check_tag.outputs.exists == 'false' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: packages | |
| path: artifacts/packages | |
| - name: Publish to NuGet | |
| if: steps.check_tag.outputs.exists == 'false' | |
| run: | | |
| for package in artifacts/packages/*.nupkg; do | |
| echo "Publishing $package..." | |
| dotnet nuget push "$package" \ | |
| --api-key ${{ secrets.NUGET_API_KEY }} \ | |
| --source https://api.nuget.org/v3/index.json \ | |
| --skip-duplicate || true | |
| done | |
| - name: Create Git tag | |
| if: steps.check_tag.outputs.exists == 'false' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -a "v${{ steps.version.outputs.version }}" -m "Release v${{ steps.version.outputs.version }}" | |
| git push origin "v${{ steps.version.outputs.version }}" | |
| - name: Generate release notes | |
| if: steps.check_tag.outputs.exists == 'false' | |
| id: release_notes | |
| env: | |
| RELEASE_VERSION: ${{ steps.version.outputs.version }} | |
| MLX_TAG: ${{ steps.mlx_version.outputs.tag }} | |
| MLX_COMMIT: ${{ steps.mlx_version.outputs.commit }} | |
| run: | | |
| PREVIOUS_TAG=$(git describe --abbrev=0 --tags $(git rev-list --tags --skip=1 --max-count=1) 2>/dev/null || echo "") | |
| if [ -z "$PREVIOUS_TAG" ]; then | |
| COMMITS=$(git log --pretty=format:"- %s (%h)" --reverse) | |
| else | |
| COMMITS=$(git log ${PREVIOUS_TAG}..HEAD --pretty=format:"- %s (%h)" --reverse) | |
| fi | |
| echo "## What's Changed" > release_notes.md | |
| echo "" >> release_notes.md | |
| echo "$COMMITS" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "## Upstream MLX" >> release_notes.md | |
| echo "- Version: ${MLX_TAG}" >> release_notes.md | |
| echo "- Commit: ${MLX_COMMIT}" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "## NuGet Packages" >> release_notes.md | |
| echo "- [MLXSharp v${RELEASE_VERSION}](https://www.nuget.org/packages/MLXSharp/${RELEASE_VERSION})" >> release_notes.md | |
| echo "- [MLXSharp.SemanticKernel v${RELEASE_VERSION}](https://www.nuget.org/packages/MLXSharp.SemanticKernel/${RELEASE_VERSION})" >> release_notes.md | |
| cat release_notes.md | |
| - name: Create GitHub Release | |
| if: steps.check_tag.outputs.exists == 'false' | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: v${{ steps.version.outputs.version }} | |
| name: Release v${{ steps.version.outputs.version }} | |
| body_path: release_notes.md | |
| files: artifacts/packages/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |