name: Continuous Integration on: push: branches: [ main, develop ] pull_request: branches: [ main, develop ] schedule: # Run tests daily at 2 AM UTC - cron: '0 2 * * *' env: CARGO_TERM_COLOR: always RUST_BACKTRACE: 1 jobs: test: name: Test Suite runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] rust: [stable, beta, nightly] exclude: # Reduce matrix size by excluding some combinations - os: windows-latest rust: beta - os: windows-latest rust: nightly - os: macos-latest rust: beta include: # Add minimum supported Rust version - os: ubuntu-latest rust: 1.70.0 steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} components: rustfmt, clippy - name: Cache Cargo registry uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ runner.os }}-cargo-${{ matrix.rust }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo-${{ matrix.rust }}- ${{ runner.os }}-cargo- - name: Install system dependencies (Ubuntu) if: matrix.os == 'ubuntu-latest' run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Install system dependencies (macOS) if: matrix.os == 'macos-latest' run: | brew update brew install pkg-config freetype jpeg libpng - name: Check code formatting if: matrix.rust == 'stable' run: cargo fmt --all -- --check - name: Run Clippy lints (library only) if: matrix.rust == 'stable' run: cargo clippy --lib -- -D warnings - name: Build project (no extra features) run: cargo build --verbose - name: Run unit tests run: cargo test --verbose --lib - name: Run integration tests (opt-in) if: contains(github.event.head_commit.message, '[integration]') run: cargo test --verbose --test args_tests - name: Run doc tests (opt-in) if: contains(github.event.head_commit.message, '[full-ci]') run: cargo test --verbose --doc - name: Test with minimal features (opt-in) if: contains(github.event.head_commit.message, '[full-ci]') run: cargo test --verbose --no-default-features --lib - name: Test with all features (opt-in) if: contains(github.event.head_commit.message, '[full-ci]') run: cargo test --verbose --all-features --lib security: name: Security Audit runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Cache Cargo registry uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target key: ubuntu-cargo-audit-${{ hashFiles('**/Cargo.lock') }} - name: Install cargo-audit run: cargo install cargo-audit - name: Run security audit run: cargo audit - name: Install cargo-deny run: cargo install cargo-deny - name: Check licenses and dependencies run: cargo deny check coverage: name: Code Coverage runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov - name: Generate coverage report (library only) run: | cargo llvm-cov --lib --workspace --lcov --output-path lcov.info - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: files: lcov.info fail_ci_if_error: true token: ${{ secrets.CODECOV_TOKEN }} benchmarks: name: Performance Benchmarks runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Cache Cargo registry uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target key: ubuntu-cargo-bench-${{ hashFiles('**/Cargo.lock') }} - name: Run benchmarks run: cargo bench --all-features - name: Store benchmark results uses: benchmark-action/github-action-benchmark@v1 with: tool: 'cargo' output-file-path: target/criterion/reports/index.html github-token: ${{ secrets.GITHUB_TOKEN }} auto-push: true comment-on-alert: true alert-threshold: '200%' fail-on-alert: true memory-safety: name: Memory Safety Check runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@nightly with: components: rust-src - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Install Miri run: rustup component add miri - name: Run Miri tests run: | cargo miri setup # Run a subset of tests with Miri (full test suite might be too slow) cargo miri test --lib -- --test-threads=1 env: MIRIFLAGS: -Zmiri-strict-provenance docker: if: contains(github.event.head_commit.message, '[docker]') name: Docker Build Test runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image run: | cat > Dockerfile << 'EOF' FROM rust:1.75 as builder WORKDIR /app COPY . . RUN apt-get update && apt-get install -y \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev RUN cargo build --release FROM debian:bookworm-slim RUN apt-get update && apt-get install -y \ libssl3 \ libfontconfig1 \ libfreetype6 \ libjpeg62-turbo \ libpng16-16 \ ca-certificates \ && rm -rf /var/lib/apt/lists/* COPY --from=builder /app/target/release/docx-mcp /usr/local/bin/ EXPOSE 8080 CMD ["docx-mcp"] EOF docker buildx build --tag docx-mcp:test . - name: Test Docker container run: | # Start container in background docker run -d --name docx-mcp-test -p 8080:8080 docx-mcp:test sleep 10 # Basic health check (adapt based on your server's health endpoint) docker logs docx-mcp-test docker stop docx-mcp-test docker rm docx-mcp-test release-check: name: Release Readiness runs-on: ubuntu-latest if: github.event_name == 'push' && github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Check that release builds (library only) run: cargo build --release - name: Verify package can be published run: cargo package --dry-run - name: Generate documentation run: cargo doc --all-features --no-deps - name: Check documentation links run: cargo doc --all-features --no-deps --open || true integration: if: contains(github.event.head_commit.message, '[integration]') name: Integration Tests runs-on: ubuntu-latest services: # Add any services your integration tests might need # For example, if you need a test database or cache redis: image: redis:7-alpine ports: - 6379:6379 options: >- --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Run integration tests (focused) run: | export RUST_LOG=debug cargo test --test args_tests -- --nocapture --test-threads=1 env: RUST_LOG: debug stress-test: name: Stress Testing runs-on: ubuntu-latest if: github.event_name == 'schedule' || contains(github.event.head_commit.message, '[stress-test]') timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable - name: Install system dependencies run: | sudo apt-get update sudo apt-get install -y \ build-essential \ pkg-config \ libssl-dev \ libfontconfig1-dev \ libfreetype6-dev \ libjpeg-dev \ libpng-dev - name: Build in release mode run: cargo build --release --all-features - name: Run stress tests run: | export STRESS_TEST=1 export RUST_LOG=info cargo test --release --test performance_tests -- --ignored --test-threads=1 cargo test --release --test e2e_workflow_tests -- --ignored --test-threads=1 notify: name: Notify Results runs-on: ubuntu-latest needs: [test, security, coverage, benchmarks] if: always() && (github.event_name == 'push' && github.ref == 'refs/heads/main') steps: - name: Notify on success if: ${{ needs.test.result == 'success' && needs.security.result == 'success' && (needs.coverage.result == 'success' || needs.coverage.result == 'skipped') }} run: | echo "✅ All CI checks passed for main branch!" # Add webhook notification here if needed - name: Notify on failure if: ${{ needs.test.result == 'failure' || needs.security.result == 'failure' || needs.coverage.result == 'failure' }} run: | echo "❌ CI checks failed for main branch!" # Add failure notification here if needed exit 1