- Remove KCL ecosystem (~220 files deleted) - Migrate all infrastructure to Nickel schema system - Consolidate documentation: legacy docs → provisioning/docs/src/ - Add CI/CD workflows (.github/) and Rust build config (.cargo/) - Update core system for Nickel schema parsing - Update README.md and CHANGES.md for v5.0.0 release - Fix pre-commit hooks: end-of-file, trailing-whitespace - Breaking changes: KCL workspaces require migration - Migration bridge available in docs/src/development/
446 lines
16 KiB
Plaintext
446 lines
16 KiB
Plaintext
# 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
|