# CI/CD Just Recipes # Generated by dev-system/ci - Dynamic template # Provides `just` recipes for running CI checks locally # Based on detected languages and enabled tools # Run all CI checks ci-full: ci-lint-rust ci-fmt-toml ci-lint-toml ci-lint-nushell ci-lint-nickel ci-lint-bash ci-lint-markdown ci-lint-prose ci-test ci-audit @echo "โœ… All CI checks passed!" # ============================================================================== # Formatting Checks # ============================================================================== # Check Rust code formatting (excludes nu_plugins which are maintained separately) ci-fmt-check: #!/usr/bin/env bash echo "๐Ÿ“ Checking Rust code formatting..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Checking: $project_name" (cd "$project_dir" && cargo +nightly fmt --all -- --check) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ All Rust projects formatted correctly" exit 0 else echo " โŒ $FAILED project(s) have formatting issues" exit 1 fi ci-fmt: #!/usr/bin/env bash echo "๐Ÿ“ Checking Rust code formatting..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Checking: $project_name" # (cd "$project_dir" && cargo +nightly fmt --all -- --check) || FAILED=$((FAILED+1)) (cd "$project_dir" && cargo +nightly fmt --all) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ All Rust projects formatted correctly" exit 0 else echo " โŒ $FAILED project(s) have formatting issues" exit 1 fi # Check TOML file formatting ci-fmt-toml: @echo "๐Ÿ“ Checking TOML formatting..." @command -v taplo >/dev/null || (echo "โŒ taplo not installed: cargo install taplo-cli"; exit 1) taplo format --check # Format all code (excludes nu_plugins which are maintained separately) fmt: #!/usr/bin/env bash echo "๐ŸŽจ Formatting Rust code..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Formatting: $project_name" (cd "$project_dir" && cargo +nightly fmt --all) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" else if [ $FAILED -eq 0 ]; then echo " โœ“ All Rust projects formatted" else echo " โŒ $FAILED project(s) failed formatting" exit 1 fi fi echo "" just fmt-toml # Format TOML files fmt-toml: @echo "๐ŸŽจ Formatting TOML files..." @command -v taplo >/dev/null || (echo "โŒ taplo not installed: cargo install taplo-cli"; exit 1) taplo format # ============================================================================== # Linting # ============================================================================== # Run all linting checks ci-lint: ci-lint-rust ci-lint-toml ci-lint-nushell ci-lint-nickel ci-lint-bash ci-lint-markdown ci-lint-prose @echo "โœ… All lint checks passed!" # Lint Rust code (excludes nu_plugins which are maintained separately) ci-lint-rust: #!/usr/bin/env bash echo "๐Ÿ” Linting Rust (clippy)..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Linting: $project_name" (cd "$project_dir" && cargo clippy --all-targets --all-features -- -D warnings) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ All Rust projects passed clippy" exit 0 else echo " โŒ $FAILED project(s) have clippy warnings" exit 1 fi # Lint TOML files (excluding .wrks, .coder, .claude, .project-tools directories) ci-lint-toml: @echo "๐Ÿ” Linting TOML files..." @command -v taplo >/dev/null || (echo "โŒ taplo not installed: cargo install taplo-cli"; exit 1) fd -t f '\.toml$' --exclude '.wrks' --exclude '.coder' --exclude '.claude' --exclude '.project-tools' | \ xargs taplo lint # Lint Nushell scripts ci-lint-nushell: #!/usr/bin/env bash echo "๐Ÿ” Validating Nushell scripts..." SCRIPTS=$(find . -name "*.nu" -type f \ ! -path "./target/*" \ ! -path "./.git/*" \ ! -path "./node_modules/*" \ | head -20) if [ -z "$SCRIPTS" ]; then echo " โ„น๏ธ No Nushell scripts found" exit 0 fi for script in $SCRIPTS; do echo " Checking: $script" nu --ide-check 100 "$script" || exit 1 done echo " โœ“ All Nushell scripts valid" # Lint Nickel schemas ci-lint-nickel: #!/usr/bin/env bash echo "๐Ÿ” Type checking Nickel..." SCHEMAS=$(find . -name "*.ncl" -type f \ ! -path "./target/*" \ ! -path "./.git/*" \ ! -path "./.coder/*" \ ! -path "./.wrks/*" \ ! -path "./.claude/*" \ ! -path "./.project-tools/*" \ ! -path "./node_modules/*" \ | head -50) if [ -z "$SCHEMAS" ]; then echo " โ„น๏ธ No Nickel schemas found" exit 0 fi # If NICKEL_IMPORT_PATH not set, construct from relative paths if [ -z "$NICKEL_IMPORT_PATH" ]; then IMPORT_PATHS="." # Add local typedialog schemas if they exist [ -d ".typedialog/provisioning/schemas" ] && IMPORT_PATHS="$IMPORT_PATHS:.typedialog/provisioning/schemas" [ -d ".typedialog/provisioning/validators" ] && IMPORT_PATHS="$IMPORT_PATHS:.typedialog/provisioning/validators" [ -d ".typedialog/provisioning/defaults" ] && IMPORT_PATHS="$IMPORT_PATHS:.typedialog/provisioning/defaults" [ -d "schemas" ] && IMPORT_PATHS="$IMPORT_PATHS:schemas" export NICKEL_IMPORT_PATH="$IMPORT_PATHS" echo " โ„น๏ธ Using NICKEL_IMPORT_PATH: $NICKEL_IMPORT_PATH" fi for schema in $SCHEMAS; do echo " Checking: $schema" nickel typecheck "$schema" || exit 1 done echo " โœ“ All Nickel schemas valid" # Lint Bash scripts ci-lint-bash: #!/usr/bin/env bash echo "๐Ÿ” Linting Bash scripts..." SCRIPTS=$(find . -name "*.sh" -o -name "*.bash" \ ! -path "*/target/*" \ ! -path "*/.git/*" \ ! -path "*/.coder/*" \ ! -path "*/.wrks/*" \ ! -path "*/.claude/*" \ ! -path "*/.project-tools/*" \ ! -path "*/node_modules/*" \ | head -50) if [ -z "$SCRIPTS" ]; then echo " โ„น๏ธ No Bash scripts found" exit 0 fi for script in $SCRIPTS; do echo " Checking: $script" shellcheck "$script" || exit 1 done echo " โœ“ All Bash scripts valid" # Lint Markdown files ci-lint-markdown: @echo "๐Ÿ” Linting Markdown files (excluding generated/build directories)..." @command -v markdownlint-cli2 >/dev/null || (echo "โŒ markdownlint-cli2 not installed: npm install markdownlint-cli2"; exit 1) markdownlint-cli2 "**/*.md" "#node_modules" "#.git" "#.typedialog" "#.coder" "#.wrks" "#.claude" "#.project-tools" "#target" "#dist" "#build" # Lint prose/documentation ci-lint-prose: #!/usr/bin/env bash echo "๐Ÿ” Linting prose with Vale (excluding generated directories)..." command -v vale >/dev/null || (echo "โŒ vale not installed: brew install vale"; exit 1) vale sync # Lint markdown files in docs directories only (excluding generated/archived directories) timeout 60 find . -name "*.md" \ ! -path "*/target/*" \ ! -path "*/.git/*" \ ! -path "*/.coder/*" \ ! -path "*/.wrks/*" \ ! -path "*/.claude/*" \ ! -path "*/.project-tools/*" \ ! -path "*/.typedialog/*" \ ! -path "*/node_modules/*" \ ! -path "*/dist/*" \ ! -path "*/build/*" \ -print0 | xargs -0 -r timeout 30 vale --no-wrap . || true echo " โœ“ Prose linting completed" # ============================================================================== # Testing # ============================================================================== # Run all tests (excludes nu_plugins which are maintained separately) ci-test: #!/usr/bin/env bash echo "๐Ÿงช Running tests..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Testing: $project_name" (cd "$project_dir" && cargo test --all-features) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ All tests passed" exit 0 else echo " โŒ $FAILED project(s) have test failures" exit 1 fi # Run tests with coverage (requires cargo-llvm-cov; excludes nu_plugins) ci-test-coverage: #!/usr/bin/env bash echo "๐Ÿ“Š Running tests with coverage..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Coverage: $project_name" (cd "$project_dir" && cargo llvm-cov --all-features --lcov --output-path lcov.info) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ Coverage reports generated" exit 0 else echo " โŒ $FAILED project(s) failed coverage" exit 1 fi # ============================================================================== # Security Auditing # ============================================================================== # Run all security audits ci-audit: ci-audit-rust @echo "โœ… All security audits passed!" # Audit Rust dependencies (excludes nu_plugins which are maintained separately) ci-audit-rust: #!/usr/bin/env bash echo "๐Ÿ”’ Auditing Rust dependencies..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Auditing: $project_name" (cd "$project_dir" && cargo audit && cargo deny check licenses && cargo deny check advisories) || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ All security audits passed" exit 0 else echo " โŒ $FAILED project(s) have security issues" exit 1 fi # Generate SBOM (excludes nu_plugins which are maintained separately) ci-sbom: #!/usr/bin/env bash echo "๐Ÿ“ฆ Generating Software Bill of Materials..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") sbom_file="$project_dir/sbom-$project_name.json" echo " Generating SBOM: $project_name" (cd "$project_dir" && cargo sbom > "$sbom_file") || FAILED=$((FAILED+1)) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ SBOM files generated" exit 0 else echo " โŒ $FAILED project(s) failed SBOM generation" exit 1 fi # ============================================================================== # Documentation # ============================================================================== # Check documentation (excludes nu_plugins which are maintained separately) ci-docs: #!/usr/bin/env bash echo "๐Ÿ“š Checking documentation..." REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".") FOUND=0 FAILED=0 for cargo_file in $(find "$REPO_ROOT" -name "Cargo.toml" -type f ! -path "*/target/*" ! -path "*/.git/*" ! -path "*/plugins/nushell-plugins/*"); do project_dir=$(dirname "$cargo_file") project_name=$(basename "$project_dir") echo " Checking docs: $project_name" (cd "$project_dir" && cargo doc --no-deps --document-private-items 2>&1 | grep -i "warning:" && FAILED=$((FAILED+1)) || true) FOUND=$((FOUND+1)) done if [ $FOUND -eq 0 ]; then echo " โ„น๏ธ No Rust projects found (nu_plugins are excluded)" exit 0 fi if [ $FAILED -eq 0 ]; then echo " โœ“ Documentation check passed" exit 0 else echo " โŒ $FAILED project(s) have doc warnings" exit 1 fi # ============================================================================== # Pre-commit Setup # ============================================================================== # Install pre-commit hooks setup-hooks: @echo "๐Ÿช Installing pre-commit hooks..." @if command -v pre-commit &> /dev/null; then \ pre-commit install && pre-commit install --hook-type pre-push; \ echo "โœ“ Pre-commit hooks installed"; \ else \ echo "โŒ pre-commit not found. Install with: pip install pre-commit"; \ exit 1; \ fi # Run pre-commit on all files hooks-run-all: @echo "๐Ÿช Running pre-commit on all files..." pre-commit run --all-files # ============================================================================== # Utility Commands # ============================================================================== # Note: Use `just clean` from main justfile for full cleanup