name: CI
on:
push:
branches: [ main, master ]
tags:
- 'v/*'
pull_request:
branches: [ main, master ]
schedule:
- cron: '0 0 * * 0'
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: "-Dwarnings"
jobs:
test:
name: Test Suite
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable, beta, 1.70.0] exclude:
- os: windows-latest
rust: beta
- os: windows-latest
rust: 1.70.0
- os: macos-latest
rust: beta
- os: macos-latest
rust: 1.70.0
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
components: rustfmt, clippy
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.os }}-${{ matrix.rust }}
- name: Install system dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y bc time
- name: Install system dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
# macOS already has bc and time
echo "No additional dependencies needed"
- name: Check formatting
run: cargo fmt --all -- --check
if: matrix.rust == 'stable'
- name: Run Clippy
run: cargo clippy --all-targets --all-features -- -D warnings
if: matrix.rust == 'stable'
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: Build release
run: cargo build --release --verbose
- name: Test release binary exists
shell: bash
run: |
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
test -f target/release/sort.exe
else
test -f target/release/sort
fi
- name: Basic functionality test
shell: bash
run: |
# Create test data
printf "3\n1\n2\n" > test.txt
# Test basic sorting
if [[ "${{ matrix.os }}" == "windows-latest" ]]; then
./target/release/sort.exe test.txt > output.txt
else
./target/release/sort test.txt > output.txt
fi
# Check output - simplified cross-platform test
# Extract just the numbers and check they're in order
sorted_output=$(cat output.txt | tr -d '\r' | tr '\n' ' ')
expected="1 2 3 "
if [[ "$sorted_output" != "$expected" ]]; then
echo "Basic sort test failed"
echo "Expected: $expected"
echo "Got: $sorted_output"
echo "Raw output:"
cat output.txt | od -c
exit 1
fi
echo "✅ Basic functionality test passed"
benchmark:
name: Performance Benchmarks
runs-on: ubuntu-latest
needs: test
if: github.event_name == 'pull_request'
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y bc time coreutils
- name: Build release
run: cargo build --release
- name: Run benchmarks
run: |
chmod +x benchmark.sh
./benchmark.sh 2>&1 | tee benchmark_results.txt
- name: Check performance regression
run: |
# Extract performance data and check for major regressions
# This is a placeholder - would implement actual regression detection
echo "Benchmark completed successfully"
grep -E "(✓|✗)" benchmark_results.txt || true
- name: Upload benchmark results
uses: actions/upload-artifact@v4
with:
name: benchmark-results
path: benchmark_results.txt
security:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run security audit
run: cargo audit
coverage:
name: Code Coverage
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@cargo-llvm-cov
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Generate code coverage
run: cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: lcov.info
fail_ci_if_error: false
verbose: true
continue-on-error: true
docs:
name: Documentation
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Build documentation
run: cargo doc --no-deps --all-features
release:
name: Build and Release
runs-on: ${{ matrix.os }}
needs: test
if: startsWith(github.ref, 'refs/tags/v/')
permissions:
contents: write
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
name: linux-x86_64
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
name: linux-aarch64
use_cross: true
- os: ubuntu-latest
target: i686-unknown-linux-gnu
name: linux-i686
use_cross: true
- os: windows-latest
target: x86_64-pc-windows-msvc
name: windows-x86_64
ext: .exe
- os: windows-latest
target: aarch64-pc-windows-msvc
name: windows-aarch64
ext: .exe
- os: macos-latest
target: x86_64-apple-darwin
name: macos-x86_64
- os: macos-latest
target: aarch64-apple-darwin
name: macos-aarch64
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cross compilation tool
if: matrix.use_cross == true
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Build release binary (cross)
if: matrix.use_cross == true
run: cross build --release --target ${{ matrix.target }}
- name: Build release binary (cargo)
if: matrix.use_cross != true
run: cargo build --release --target ${{ matrix.target }}
- name: Create release archive
shell: bash
run: |
mkdir -p release
if [[ -n "${{ matrix.ext }}" ]]; then
binary_name="sort${{ matrix.ext }}"
else
binary_name="sort"
fi
archive_name="rust-sort-${{ matrix.name }}.tar.gz"
echo "🔍 Debug info:"
echo " Platform: ${{ matrix.name }}"
echo " Target: ${{ matrix.target }}"
echo " Binary: $binary_name"
echo " Archive: $archive_name"
echo " Working dir: $(pwd)"
echo "📂 Target directory contents:"
ls -la target/${{ matrix.target }}/release/ || echo "❌ Target dir not found"
cd target/${{ matrix.target }}/release
if [[ -f "$binary_name" ]]; then
tar -czf "../../../release/$archive_name" "$binary_name"
echo "✅ Created: release/$archive_name"
ls -la "../../../release/$archive_name"
else
echo "❌ Binary not found: $binary_name"
echo "Available files:"
ls -la .
exit 1
fi
cd -
echo "📦 Final release directory:"
ls -la release/
- name: Debug files before release
shell: bash
run: |
echo "🔍 Files to upload:"
ls -la release/ || echo "❌ No release directory"
echo "📊 File count: $(ls release/*.tar.gz 2>/dev/null | wc -l)"
if ls release/*.tar.gz >/dev/null 2>&1; then
echo "📋 Files:"
for file in release/*.tar.gz; do
echo " - $(basename $file) ($(du -h $file | cut -f1))"
done
fi
- name: Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: "🦀 Rust Sort ${{ github.ref_name }}"
body: |
## What's Changed in ${{ github.ref_name }}
🚀 **High-performance Rust implementation of GNU sort**
### Features
* Zero-copy operations for maximum performance
* SIMD-optimized comparisons
* Multi-threaded parallel sorting
* Field-based sorting (-k option)
* Locale-aware string comparison
* Cross-platform compatibility
### Supported Platforms
* Linux: x86_64, aarch64, i686
* Windows: x86_64, aarch64
* macOS: x86_64, aarch64
**Platform: ${{ matrix.name }} (${{ matrix.target }})**
files: |
./release/*.tar.gz
draft: false
prerelease: false
token: ${{ secrets.GITHUB_TOKEN }}
build-matrix:
name: Build Release Binaries
runs-on: ${{ matrix.os }}
needs: test
if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master'
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
use_cross: true
- os: windows-latest
target: x86_64-pc-windows-msvc
- os: windows-latest
target: aarch64-pc-windows-msvc
- os: macos-latest
target: x86_64-apple-darwin
- os: macos-latest
target: aarch64-apple-darwin
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Install cross compilation tool
if: matrix.use_cross == true
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Build release binary (cross)
if: matrix.use_cross == true
run: cross build --release --target ${{ matrix.target }}
- name: Build release binary (cargo)
if: matrix.use_cross != true
run: cargo build --release --target ${{ matrix.target }}
publish:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: [test]
if: startsWith(github.ref, 'refs/tags/v/')
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Setup Rust cache
uses: Swatinem/rust-cache@v2
- name: Publish to crates.io
run: cargo publish --allow-dirty --token ${{ secrets.CARGO_REGISTRY_TOKEN }}
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}