name: CI/CD
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
release:
types: [published]
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]
exclude:
- os: windows-latest
rust: beta
- os: macos-latest
rust: beta
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-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Install system dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev pkg-config
- name: Check formatting
run: cargo fmt --all -- --check
- name: Check clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run unit tests
run: cargo test --lib --verbose
- name: Run integration tests (without API keys)
run: cargo test --test integration_tests --verbose
continue-on-error: true
- name: Test documentation
run: cargo doc --no-deps --all-features
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: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- 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 code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: llvm-tools-preview
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev pkg-config
- name: Install cargo-llvm-cov
run: cargo install cargo-llvm-cov
- name: Generate coverage report
run: cargo llvm-cov --lib --lcov --output-path lcov.info
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
file: lcov.info
fail_ci_if_error: false
build:
name: Build Binaries
needs: [test, security]
runs-on: ${{ matrix.os }}
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
artifact_name: commitor
asset_name: commitor-linux-x86_64
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
artifact_name: commitor
asset_name: commitor-linux-x86_64-musl
- os: windows-latest
target: x86_64-pc-windows-msvc
artifact_name: commitor.exe
asset_name: commitor-windows-x86_64.exe
- os: macos-latest
target: x86_64-apple-darwin
artifact_name: commitor
asset_name: commitor-macos-x86_64
- os: macos-latest
target: aarch64-apple-darwin
artifact_name: commitor
asset_name: commitor-macos-aarch64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install system dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev pkg-config
if [ "${{ matrix.target }}" = "x86_64-unknown-linux-musl" ]; then
sudo apt-get install -y musl-tools
fi
- name: Build binary
run: cargo build --release --target ${{ matrix.target }}
- name: Strip binary (Unix)
if: matrix.os != 'windows-latest'
run: strip target/${{ matrix.target }}/release/${{ matrix.artifact_name }}
- name: Rename binary
shell: bash
run: |
mkdir -p artifacts
if [ "${{ matrix.os }}" = "windows-latest" ]; then
cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} artifacts/${{ matrix.asset_name }}
else
cp target/${{ matrix.target }}/release/${{ matrix.artifact_name }} artifacts/${{ matrix.asset_name }}
fi
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.asset_name }}
path: artifacts/${{ matrix.asset_name }}
docker:
name: Build Docker Image
needs: [test, security]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to Docker Hub
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: simonhdickson/commitor
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
release:
name: Create Release
if: github.event_name == 'release'
needs: [build]
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Create release assets
run: |
cd artifacts
for dir in */; do
if [ -d "$dir" ]; then
cd "$dir"
tar -czf "../${dir%/}.tar.gz" *
cd ..
fi
done
- name: Upload release assets
uses: softprops/action-gh-release@v1
with:
files: |
artifacts/*.tar.gz
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
benchmark:
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: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libssl-dev pkg-config
- name: Run benchmarks
run: |
cargo test --release --test '*' -- --ignored benchmark
continue-on-error: true
notify:
name: Notify Status
runs-on: ubuntu-latest
needs: [test, security, coverage, build]
if: always() && github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Notify success
if: needs.test.result == 'success' && needs.security.result == 'success' && needs.build.result == 'success'
run: |
echo "✅ All CI checks passed successfully!"
echo "Build artifacts are ready for deployment."
- name: Notify failure
if: needs.test.result == 'failure' || needs.security.result == 'failure' || needs.build.result == 'failure'
run: |
echo "❌ CI pipeline failed. Please check the logs."
echo "Test result: ${{ needs.test.result }}"
echo "Security result: ${{ needs.security.result }}"
echo "Build result: ${{ needs.build.result }}"
exit 1