mirror of
https://fastgit.cc/github.com/Michael-A-Kuykendall/shimmy
synced 2026-05-01 06:12:44 +08:00
- Add CROSS_NO_WARNINGS=1 to build environment - Prevents unused Cross.toml key warnings from failing builds - Cross.toml has macOS-specific config that warns on Linux ARM64 builds - Fixes Issue #131 ARM64 release builds Signed-off-by: Michael A. Kuykendall <michaelallenkuykendall@gmail.com>
361 lines
15 KiB
YAML
361 lines
15 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
branches:
|
|
- test-release # Test on specific branch
|
|
workflow_dispatch: # Allow manual testing
|
|
|
|
jobs:
|
|
# 🚧 MANDATORY RELEASE GATES - ALL MUST PASS OR ENTIRE RELEASE STOPS
|
|
preflight:
|
|
name: "🚧 Release Gates - MANDATORY VALIDATION"
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
should_publish: ${{ steps.gates.outputs.should_publish }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: "🚧 GATE 1/7: Core Build Validation"
|
|
run: |
|
|
echo "::group::Gate 1: Core Build"
|
|
cargo build --release --no-default-features --features huggingface
|
|
echo "✅ Core build successful"
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 2/7: CUDA Build Validation (No Timeout - Can Take Hours)"
|
|
run: |
|
|
echo "::group::Gate 2: CUDA Build"
|
|
echo "⏳ CUDA compilation can take 19+ hours - letting it run to natural completion"
|
|
|
|
# Check if CUDA Toolkit is available first
|
|
if command -v nvcc >/dev/null 2>&1; then
|
|
echo "✅ CUDA Toolkit found, attempting CUDA build..."
|
|
cargo build --release --no-default-features --features llama-cuda
|
|
echo "✅ CUDA build completed successfully"
|
|
else
|
|
echo "⚠️ CUDA Toolkit not found on runner (nvcc not available)"
|
|
echo "🔄 Validating CPU-only llama build instead..."
|
|
|
|
# Validate that CPU-only llama build works
|
|
cargo build --release --no-default-features --features llama
|
|
echo "✅ CPU-only llama build completed successfully"
|
|
echo "📝 Note: CUDA validation skipped - this is expected on standard GitHub runners"
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 3/7: Template Packaging Validation (Issue #60 Protection)"
|
|
run: |
|
|
echo "::group::Gate 3: Template Packaging"
|
|
# Check for Docker templates with OS-agnostic path handling
|
|
# Use --allow-dirty to handle uncommitted Cargo.lock changes from dependency resolution
|
|
if cargo package --allow-dirty --list | grep -E "(^|[/\\\\])templates[/\\\\]docker[/\\\\]Dockerfile$" > /dev/null; then
|
|
echo "✅ Docker templates properly included in package"
|
|
else
|
|
echo "❌ Required Docker template missing from package - Issue #60 regression!"
|
|
echo "Package contents:"
|
|
cargo package --allow-dirty --list | grep -i docker || echo "No docker files found"
|
|
exit 1
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 4/7: Binary Size Constitutional Limit (20MB)"
|
|
run: |
|
|
echo "::group::Gate 4: Binary Size"
|
|
size=$(stat -c%s target/release/shimmy 2>/dev/null || echo "0")
|
|
max_size=$((20 * 1024 * 1024))
|
|
if [ "$size" -gt "$max_size" ]; then
|
|
echo "❌ Binary size ${size} exceeds constitutional limit of ${max_size} bytes"
|
|
exit 1
|
|
fi
|
|
echo "✅ Binary size ${size} bytes within constitutional limit"
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 5/7: Test Suite Validation"
|
|
run: |
|
|
echo "::group::Gate 5: Tests"
|
|
# Run tests that don't require model files (exclude integration tests needing .gguf files)
|
|
cargo test --lib --no-default-features --features huggingface -- --skip test_generate_handler --skip test_chat_completions
|
|
echo "✅ Core tests passing"
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 5.5/7: Issue Regression Tests"
|
|
run: |
|
|
echo "::group::Gate 5.5: Issue Regression Prevention"
|
|
echo "🔄 Running issue-specific regression tests to prevent user-reported bug regressions..."
|
|
|
|
# Test Issue #111 - GPU metrics endpoint
|
|
cargo test --test regression_tests test_issue_111_gpu_metrics_endpoint --no-default-features --features huggingface
|
|
echo "✅ Issue #111 (GPU metrics): Regression test passed"
|
|
|
|
# Test Issue #112 - SafeTensors engine selection
|
|
cargo test --test regression_tests test_issue_112_safetensors_engine_selection --no-default-features --features huggingface
|
|
echo "✅ Issue #112 (SafeTensors): Regression test passed"
|
|
|
|
# Test Issue #113 - OpenAI API frontend compatibility
|
|
cargo test --test regression_tests test_issue_113_openai_api_frontend_compatibility --no-default-features --features huggingface
|
|
echo "✅ Issue #113 (OpenAI compatibility): Regression test passed"
|
|
|
|
# Test Issue #114 - MLX distribution features
|
|
cargo test --test regression_tests test_issue_114_mlx_distribution_features --no-default-features --features huggingface
|
|
echo "✅ Issue #114 (MLX distribution): Regression test passed"
|
|
|
|
# Test Issue #13 - Qwen model template detection
|
|
cargo test --test regression_tests test_qwen_model_template_detection --no-default-features --features huggingface
|
|
echo "✅ Issue #13 (Qwen templates): Regression test passed"
|
|
|
|
# Test Issue #12 - Custom model directories
|
|
cargo test --test regression_tests test_custom_model_directory_environment_variables --no-default-features --features huggingface
|
|
echo "✅ Issue #12 (Custom directories): Regression test passed"
|
|
|
|
echo "✅ All issue regression tests passed - no user-reported bug regressions detected"
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 6/7: Documentation Validation"
|
|
run: |
|
|
echo "::group::Gate 6: Documentation"
|
|
|
|
# Check if CUDA Toolkit is available for documentation build
|
|
if command -v nvcc >/dev/null 2>&1; then
|
|
echo "✅ CUDA Toolkit found, building docs with all features..."
|
|
cargo doc --no-deps --all-features
|
|
echo "✅ Documentation with all features built successfully"
|
|
else
|
|
echo "⚠️ CUDA Toolkit not found on runner (nvcc not available)"
|
|
echo "🔄 Building documentation without CUDA features..."
|
|
|
|
# Build docs without CUDA features to avoid build failures
|
|
cargo doc --no-deps --features "huggingface,llama,mlx"
|
|
echo "✅ Documentation built successfully (CUDA features excluded)"
|
|
echo "📝 Note: CUDA documentation skipped - this is expected on standard GitHub runners"
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: "🚧 GATE 7/7: Crates.io Publication Validation"
|
|
run: |
|
|
echo "::group::Gate 7: Crates.io Validation"
|
|
echo "🧪 Testing crates.io publication readiness..."
|
|
|
|
# Handle uncommitted Cargo.lock (common issue)
|
|
if git status --porcelain | grep -q "Cargo.lock"; then
|
|
echo "⚠️ Cargo.lock has uncommitted changes (expected from dependency resolution)"
|
|
echo "🔄 Using --allow-dirty flag for crates.io validation"
|
|
DIRTY_FLAG="--allow-dirty"
|
|
else
|
|
echo "✅ No uncommitted changes detected"
|
|
DIRTY_FLAG=""
|
|
fi
|
|
|
|
# Dry-run validation to catch issues before real release
|
|
echo "🔍 Running cargo publish --dry-run..."
|
|
if cargo publish --dry-run $DIRTY_FLAG; then
|
|
echo "✅ Crates.io dry-run validation PASSED"
|
|
echo "📦 Package builds successfully and is ready for publication"
|
|
else
|
|
echo "❌ Crates.io dry-run validation FAILED"
|
|
echo "🚫 Blocking release until crates.io issues are resolved"
|
|
exit 1
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: "🎯 RELEASE GATES SUMMARY"
|
|
id: gates
|
|
run: |
|
|
echo "🎉 ALL 8 MANDATORY GATES PASSED!"
|
|
echo "✅ Gate 1: Core Build"
|
|
echo "✅ Gate 2: CUDA Timeout Protection (Issue #59)"
|
|
echo "✅ Gate 3: Template Packaging (Issue #60)"
|
|
echo "✅ Gate 4: Binary Size Constitutional Limit"
|
|
echo "✅ Gate 5: Test Suite"
|
|
echo "✅ Gate 5.5: Issue Regression Prevention"
|
|
echo "✅ Gate 6: Documentation"
|
|
echo "✅ Gate 7: Crates.io Publication Validation"
|
|
echo "should_publish=true" >> $GITHUB_OUTPUT
|
|
|
|
# 🚀 REUSE GATE BINARIES - NO RECOMPILATION WASTE
|
|
- name: "Upload gate binaries as artifacts"
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: gate-built-binary
|
|
path: target/release/shimmy
|
|
|
|
# 🚀 LINUX BINARY - REUSE FROM GATES (NO RECOMPILATION)
|
|
reuse-gate-binary:
|
|
needs: preflight
|
|
if: needs.preflight.outputs.should_publish == 'true'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Download gate-built binary
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: gate-built-binary
|
|
path: ./
|
|
|
|
- name: Upload as Linux x86_64 artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: shimmy-linux-x86_64
|
|
path: shimmy
|
|
|
|
# 🚀 CROSS-PLATFORM BUILDS (ONLY WHAT GATES DIDN'T BUILD)
|
|
build:
|
|
needs: preflight
|
|
if: needs.preflight.outputs.should_publish == 'true'
|
|
strategy:
|
|
matrix:
|
|
include:
|
|
- os: ubuntu-latest
|
|
target: x86_64-unknown-linux-musl
|
|
binary-name: shimmy
|
|
artifact-name: shimmy-linux-x86_64-universal
|
|
|
|
- os: ubuntu-latest
|
|
target: aarch64-unknown-linux-gnu
|
|
binary-name: shimmy
|
|
artifact-name: shimmy-linux-aarch64
|
|
use-cross: true
|
|
|
|
- os: windows-latest
|
|
target: x86_64-pc-windows-msvc
|
|
binary-name: shimmy.exe
|
|
artifact-name: shimmy-windows-x86_64.exe
|
|
|
|
- os: macos-latest
|
|
target: x86_64-apple-darwin
|
|
binary-name: shimmy
|
|
artifact-name: shimmy-macos-intel
|
|
|
|
- os: macos-latest
|
|
target: aarch64-apple-darwin
|
|
binary-name: shimmy
|
|
artifact-name: shimmy-macos-arm64
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Install Rust
|
|
uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: ${{ matrix.target }}
|
|
|
|
- name: Install musl-tools (for musl builds)
|
|
if: matrix.target == 'x86_64-unknown-linux-musl'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y musl-tools musl-dev
|
|
|
|
- name: Install cross for ARM64 cross-compilation
|
|
if: matrix.use-cross == true
|
|
run: |
|
|
cargo install cross --git https://github.com/cross-rs/cross
|
|
|
|
- name: Build binary
|
|
shell: bash
|
|
env:
|
|
CROSS_NO_WARNINGS: 1
|
|
run: |
|
|
# Determine features based on platform (Issue #129: GPU support in precompiled binaries)
|
|
FEATURES="huggingface,llama"
|
|
|
|
if [[ "${{ matrix.target }}" == "x86_64-unknown-linux-musl" ]]; then
|
|
# musl builds: use huggingface-only to avoid llama.cpp C++ compilation issues
|
|
FEATURES="huggingface"
|
|
elif [[ "${{ matrix.target }}" == "aarch64-unknown-linux-gnu" ]]; then
|
|
# ARM64 Linux: CPU-only features (Issue #131)
|
|
FEATURES="huggingface,llama"
|
|
elif [[ "${{ matrix.os }}" == "windows-latest" ]]; then
|
|
# Windows: Add Vulkan support for GPU acceleration
|
|
FEATURES="huggingface,llama,llama-vulkan"
|
|
elif [[ "${{ matrix.os }}" == "macos-latest" ]]; then
|
|
# macOS: Add MLX support for Apple Silicon GPU acceleration
|
|
FEATURES="huggingface,llama,mlx"
|
|
fi
|
|
|
|
echo "Building with features: $FEATURES"
|
|
|
|
# Use cross for ARM64 cross-compilation, cargo for native builds
|
|
if [[ "${{ matrix.use-cross }}" == "true" ]]; then
|
|
cross build --release --target ${{ matrix.target }} --no-default-features --features "$FEATURES"
|
|
else
|
|
cargo build --release --target ${{ matrix.target }} --no-default-features --features "$FEATURES"
|
|
fi
|
|
|
|
- name: Upload artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: ${{ matrix.artifact-name }}
|
|
path: target/${{ matrix.target }}/release/${{ matrix.binary-name }}
|
|
|
|
release:
|
|
needs: [preflight, reuse-gate-binary, build]
|
|
runs-on: ubuntu-latest
|
|
if: startsWith(github.ref, 'refs/tags/') && needs.preflight.outputs.should_publish == 'true'
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: ./artifacts
|
|
|
|
- name: Prepare release files
|
|
run: |
|
|
mkdir -p release-files
|
|
|
|
# Copy and rename artifacts
|
|
cp artifacts/shimmy-linux-x86_64/shimmy release-files/shimmy-linux-x86_64
|
|
cp artifacts/shimmy-linux-x86_64/shimmy release-files/shimmy # Generic name
|
|
|
|
cp artifacts/shimmy-linux-aarch64/shimmy release-files/shimmy-linux-aarch64
|
|
|
|
cp artifacts/shimmy-windows-x86_64.exe/shimmy.exe release-files/shimmy-windows-x86_64.exe
|
|
cp artifacts/shimmy-windows-x86_64.exe/shimmy.exe release-files/shimmy.exe # Generic name
|
|
|
|
cp artifacts/shimmy-macos-intel/shimmy release-files/shimmy-macos-intel
|
|
cp artifacts/shimmy-macos-arm64/shimmy release-files/shimmy-macos-arm64
|
|
|
|
# List what we're releasing
|
|
echo "Release files:"
|
|
ls -la release-files/
|
|
|
|
- name: Create release
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh release create ${{ github.ref_name }} \
|
|
release-files/* \
|
|
--title "Shimmy ${{ github.ref_name }}" \
|
|
--generate-notes
|
|
|
|
- name: Install Rust for crates.io publishing
|
|
uses: dtolnay/rust-toolchain@stable
|
|
|
|
- name: "📦 Publish to crates.io"
|
|
env:
|
|
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
run: |
|
|
echo "🚀 Publishing shimmy ${{ github.ref_name }} to crates.io..."
|
|
|
|
# Handle uncommitted Cargo.lock (same logic as Gate 7)
|
|
if git status --porcelain | grep -q "Cargo.lock"; then
|
|
echo "⚠️ Cargo.lock has uncommitted changes (using --allow-dirty)"
|
|
DIRTY_FLAG="--allow-dirty"
|
|
else
|
|
echo "✅ No uncommitted changes detected"
|
|
DIRTY_FLAG=""
|
|
fi
|
|
|
|
# Publish to crates.io (dry-run already validated in Gate 7)
|
|
cargo publish $DIRTY_FLAG
|
|
|
|
echo "✅ Successfully published shimmy ${{ github.ref_name }} to crates.io!"
|
|
echo "📦 Users can now install with: cargo install shimmy"
|