446 lines
16 KiB
Plaintext
Raw Normal View History

# 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