{ description = "PhotonCloud local CI gates (Nix-first, CI-provider-agnostic)"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; rust-overlay = { url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, flake-utils, rust-overlay }: flake-utils.lib.eachDefaultSystem (system: let overlays = [ (import rust-overlay) ]; pkgs = import nixpkgs { inherit system overlays; }; # Use a complete toolchain to ensure host `std` is present under Nix # (fixes: "can't find crate for `std`"). rustToolchain = pkgs.rust-bin.stable.latest.complete; # rust-overlay components (provide cargo-fmt / clippy-driver reliably in PATH) rustfmtComponent = pkgs.rust-bin.stable.latest.rustfmt; clippyComponent = pkgs.rust-bin.stable.latest.clippy; wsList = [ "chainfire" "flaredb" "iam" "plasmavmc" "prismnet" "flashdns" "fiberlb" "lightningstor" "nightlight" "creditservice" "k8shost" ]; gate = pkgs.writeShellApplication { name = "photoncloud-gate"; runtimeInputs = with pkgs; [ bash coreutils findutils gnugrep gawk git rustToolchain rustfmtComponent clippyComponent protobuf llvmPackages.libclang llvmPackages.clang pkg-config openssl rocksdb ]; text = '' set -euo pipefail usage() { cat <<'USAGE' PhotonCloud local CI gates (provider-agnostic) Usage: photoncloud-gate [--tier 0|1|2] [--workspace ] [--no-logs] [--fix] Tiers: 0: fmt + clippy + unit tests (lib) (fast, stable default) 1: tier0 + integration tests (--tests) 2: tier1 + ignored tests (-- --ignored) Notes: - Requires running inside a git checkout (uses `git rev-parse`). - Logs are written to ./work/ci// by default (NOT .cccc/). USAGE } tier="0" only_ws="" no_logs="0" fix="0" while [[ $# -gt 0 ]]; do case "$1" in --tier) tier="$2"; shift 2;; --workspace) only_ws="$2"; shift 2;; --no-logs) no_logs="1"; shift 1;; --fix) fix="1"; shift 1;; -h|--help) usage; exit 0;; *) echo "[gate] ERROR: unknown arg: $1" >&2 usage exit 2 ;; esac done if [[ "$tier" != "0" && "$tier" != "1" && "$tier" != "2" ]]; then echo "[gate] ERROR: --tier must be 0, 1, or 2 (got: $tier)" >&2 exit 2 fi repo_root="$(git rev-parse --show-toplevel)" # Avoid .cccc/ (managed externally). Use work/ for local artifacts. timestamp="$(date -u +%Y%m%d-%H%M%S)" logdir="$repo_root/work/ci/$timestamp" if [[ "$no_logs" == "0" ]]; then mkdir -p "$logdir" echo "[gate] logs: $logdir" else echo "[gate] logs: disabled" fi # Prefer Nix-provided toolchain over user's ~/.cargo binaries. # # `nix run` keeps the user's PATH (often including ~/.cargo/bin), which can cause # cargo subcommands (cargo-fmt, etc.) to resolve outside Nix. # Force PATH to Nix-provided tools only. export PATH="${pkgs.lib.makeBinPath [ pkgs.bash pkgs.coreutils pkgs.findutils pkgs.gnugrep pkgs.gawk pkgs.git rustToolchain rustfmtComponent clippyComponent pkgs.protobuf pkgs.llvmPackages.libclang pkgs.llvmPackages.clang pkgs.pkg-config ]}" CARGO="${rustToolchain}/bin/cargo" export RUSTC="${rustToolchain}/bin/rustc" CARGO_FMT="${rustToolchain}/bin/cargo-fmt" CARGO_CLIPPY="${rustToolchain}/bin/cargo-clippy" fmt_rustfmt_args="-- --check" if [[ "$fix" == "1" ]]; then fmt_rustfmt_args="" fi export LIBCLANG_PATH="${pkgs.llvmPackages.libclang.lib}/lib"; export PROTOC="${pkgs.protobuf}/bin/protoc" export ROCKSDB_LIB_DIR="${pkgs.rocksdb}/lib" run_cmd() { local ws="$1"; shift local title="$1"; shift local cmd="$*" echo "" echo "================================================================================" echo "[gate][$ws] $title" echo "--------------------------------------------------------------------------------" echo "[gate][$ws] $cmd" echo "================================================================================" if [[ "$no_logs" == "0" ]]; then local out out="$logdir/$ws.$(echo "$title" | tr '[:upper:]' '[:lower:]' | tr ' ' '_' | tr -cd 'a-z0-9_').log" (cd "$repo_root/$ws" && bash -c "$cmd") 2>&1 | tee "$out" else (cd "$repo_root/$ws" && bash -c "$cmd") fi } for ws in ${pkgs.lib.concatStringsSep " " wsList}; do if [[ -n "$only_ws" && "$only_ws" != "$ws" ]]; then continue fi if [[ ! -f "$repo_root/$ws/Cargo.toml" ]]; then echo "[gate] WARN: skipping $ws (no Cargo.toml)" continue fi # Format gate: call Nix-provided `cargo-fmt` directly (avoid resolving ~/.cargo/bin/cargo-fmt). # # NOTE: Avoid `--all` here; with path-dependencies it may traverse outside the workspace directory. run_cmd "$ws" "fmt" "$CARGO_FMT fmt $fmt_rustfmt_args" # Lint gate: call Nix-provided `cargo-clippy` directly (avoid resolving ~/.cargo/bin/cargo-clippy). run_cmd "$ws" "clippy" "$CARGO_CLIPPY clippy --workspace --all-targets -- -D warnings" run_cmd "$ws" "test (tier0 unit)" "$CARGO test --workspace --lib" if [[ "$tier" == "1" || "$tier" == "2" ]]; then run_cmd "$ws" "test (tier1 integration)" "$CARGO test --workspace --tests" fi if [[ "$tier" == "2" ]]; then run_cmd "$ws" "test (tier2 ignored)" "$CARGO test --workspace --tests -- --ignored" fi done echo "" echo "[gate] OK (tier=$tier)" ''; }; in { packages.gate = gate; apps.gate = flake-utils.lib.mkApp { drv = gate; }; # CI-optimized gate (alias) packages.gate-ci = gate; # Checks are minimal and mirror tier0 (provider-agnostic). checks.gate-tier0 = pkgs.runCommand "photoncloud-gate-tier0" { } '' mkdir -p $out ${gate}/bin/photoncloud-gate --tier 0 --no-logs touch $out/ok ''; devShells.default = pkgs.mkShell { name = "photoncloud-ci-dev"; buildInputs = with pkgs; [ rustToolchain protobuf llvmPackages.libclang llvmPackages.clang pkg-config openssl rocksdb git ]; LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; PROTOC = "${pkgs.protobuf}/bin/protoc"; ROCKSDB_LIB_DIR = "${pkgs.rocksdb}/lib"; }; } ); }