#!/usr/bin/env bash # ────────────────────────────────────────────────────────────────────────────── # ci.sh — CI/CD build script for ccc_rust # # Usage: # ./ci.sh Run the full CI pipeline (lint + test + cross-build) # ./ci.sh lint Lint only (fmt + clippy) # ./ci.sh test Unit tests + conformance vectors # ./ci.sh build Native debug build # ./ci.sh release Native release build # ./ci.sh apple Cross-compile all Apple targets (iOS + macOS) # ./ci.sh android Cross-compile Android targets (requires NDK) # ./ci.sh all Full pipeline + all cross targets # ────────────────────────────────────────────────────────────────────────────── set -euo pipefail # Source cargo env if not already in PATH. if ! command -v cargo &>/dev/null; then # shellcheck source=/dev/null source "$HOME/.cargo/env" fi RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' BOLD='\033[1m' RESET='\033[0m' step() { echo -e "\n${CYAN}${BOLD}── $1 ──${RESET}"; } pass() { echo -e "${GREEN}✓ $1${RESET}"; } fail() { echo -e "${RED}✗ $1${RESET}"; exit 1; } # ── Submodule check ────────────────────────────────────────────────────────── check_submodule() { if [ ! -f "vendors/wolfssl/CMakeLists.txt" ]; then step "Initialising wolfSSL submodule" git submodule update --init --recursive fi } # ── Stages ─────────────────────────────────────────────────────────────────── do_lint() { step "Format check" cargo fmt --check || fail "cargo fmt --check failed" pass "Format OK" step "Clippy" cargo clippy --workspace -- -D warnings || fail "clippy failed" pass "Clippy OK" } do_test() { step "Unit tests" cargo test --workspace || fail "cargo test failed" pass "Unit tests passed" step "Conformance vectors" cargo run -p ccc-conformance-tests || fail "conformance tests failed" pass "Conformance tests passed" } do_build() { step "Build (debug)" cargo build --workspace || fail "debug build failed" pass "Debug build OK" } do_release() { step "Build (release)" cargo build --workspace --release || fail "release build failed" pass "Release build OK" } do_apple() { step "Build iOS (aarch64-apple-ios)" cargo build-ios --release || fail "iOS build failed" pass "iOS build OK" step "Build macOS ARM64 (aarch64-apple-darwin)" cargo build-macos-arm64 --release || fail "macOS ARM64 build failed" pass "macOS ARM64 build OK" step "Build macOS x64 (x86_64-apple-darwin)" cargo build-macos-x64 --release || fail "macOS x64 build failed" pass "macOS x64 build OK" } do_android() { if ! command -v aarch64-linux-android21-clang &>/dev/null; then echo -e "${RED}Android NDK not in PATH — skipping Android targets.${RESET}" echo "Set ANDROID_NDK_HOME and add the toolchain bin/ to PATH." return 1 fi step "Build Android ARM64 (aarch64-linux-android)" cargo build-android-arm64 --release || fail "Android ARM64 build failed" pass "Android ARM64 build OK" step "Build Android x64 (x86_64-linux-android)" cargo build-android-x64 --release || fail "Android x64 build failed" pass "Android x64 build OK" } do_full() { do_lint do_test do_release } do_linux() { step "Build Linux x64 (x86_64-unknown-linux-gnu)" cargo build --workspace --release --target x86_64-unknown-linux-gnu \ || fail "Linux x64 build failed" pass "Linux x64 build OK" } do_windows() { step "Build Windows x64 (x86_64-pc-windows-msvc)" cargo build --workspace --release --target x86_64-pc-windows-msvc \ || fail "Windows x64 build failed" pass "Windows x64 build OK" } do_all() { do_full do_apple do_android || true # Don't fail the pipeline if NDK is absent. } # ── Summary ────────────────────────────────────────────────────────────────── summary() { echo "" step "Artifact locations" echo " Native (release): target/release/" echo " iOS: target/aarch64-apple-ios/release/" echo " macOS ARM64: target/aarch64-apple-darwin/release/" echo " macOS x64: target/x86_64-apple-darwin/release/" echo " Linux x64: target/x86_64-unknown-linux-gnu/release/" echo " Windows x64: target/x86_64-pc-windows-msvc/release/" echo " Android ARM64: target/aarch64-linux-android/release/" echo " Android x64: target/x86_64-linux-android/release/" echo "" pass "CI pipeline complete" } # ── Main ───────────────────────────────────────────────────────────────────── check_submodule case "${1:-}" in lint) do_lint ;; test) do_test ;; build) do_build ;; release) do_release ;; apple) do_apple && summary ;; android) do_android && summary ;; linux) do_linux && summary ;; windows) do_windows && summary ;; all) do_all && summary ;; "") do_full && summary ;; *) echo "Usage: $0 {lint|test|build|release|apple|android|linux|windows|all}" exit 1 ;; esac