#!/usr/bin/env bash # # audit-missing-git.sh - Audit @ts packages for git and workflow configuration # # Scans all @ts/* directories and categorizes packages by their publishing # configuration and git/workflow setup status. # # Usage: # ./scripts/analysis/audit-missing-git.sh # Run audit # ./scripts/analysis/audit-missing-git.sh --quiet # Only show problems # # Categories: # PUBLISHABLE_NO_GIT - _.publish=true but missing .git directory # PUBLISHABLE_NO_WORKFLOW - _.publish=true but missing .forgejo/workflows/ # INTERNAL - No _.publish=true (internal/tooling packages) # PROPERLY_CONFIGURED - Has both .git and workflows set -euo pipefail # ============================================================================ # Configuration # ============================================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" WORKSPACE_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" TS_ROOT="$WORKSPACE_ROOT/@ts" QUIET_MODE=false # Parse arguments while [[ $# -gt 0 ]]; do case "$1" in --quiet|-q) QUIET_MODE=true shift ;; --help|-h) echo "Usage: $0 [--quiet]" echo "" echo "Options:" echo " --quiet, -q Only show packages with issues" echo " --help, -h Show this help" exit 0 ;; *) echo "Unknown option: $1" >&2 exit 1 ;; esac done # ============================================================================ # Data Storage # ============================================================================ declare -a PUBLISHABLE_NO_GIT=() declare -a PUBLISHABLE_NO_WORKFLOW=() declare -a INTERNAL=() declare -a PROPERLY_CONFIGURED=() # ============================================================================ # Utilities # ============================================================================ log() { echo -e "$1" >&2 } # Check if _.publish is true in package.json is_publishable() { local pkg_json="$1" local publish publish=$(jq -r '._?.publish // false' "$pkg_json" 2>/dev/null) [[ "$publish" == "true" ]] } # Get package name from package.json get_package_name() { local pkg_json="$1" jq -r '.name // "unknown"' "$pkg_json" 2>/dev/null } # ============================================================================ # Main Audit Logic # ============================================================================ audit_packages() { log "Scanning TypeScript packages in $TS_ROOT..." log "" # Find all directories in @ts/ (excluding hidden and special dirs) while IFS= read -r -d '' pkg_dir; do local dir_name dir_name=$(basename "$pkg_dir") # Skip hidden directories and special cases [[ "$dir_name" == .* ]] && continue [[ "$dir_name" == "node_modules" ]] && continue [[ "$dir_name" == "_archived" ]] && continue [[ "$dir_name" == "_archive" ]] && continue local pkg_json="$pkg_dir/package.json" local has_git=false local has_workflow=false local is_publish=false # Check for .git directory [[ -d "$pkg_dir/.git" ]] && has_git=true # Check for .forgejo/workflows directory [[ -d "$pkg_dir/.forgejo/workflows" ]] && has_workflow=true # Check package.json if [[ -f "$pkg_json" ]]; then if is_publishable "$pkg_json"; then is_publish=true fi fi # Categorize the package if [[ "$is_publish" == true ]]; then if [[ "$has_git" == false ]]; then PUBLISHABLE_NO_GIT+=("$dir_name") elif [[ "$has_workflow" == false ]]; then PUBLISHABLE_NO_WORKFLOW+=("$dir_name") else PROPERLY_CONFIGURED+=("$dir_name") fi else INTERNAL+=("$dir_name") fi done < <(find "$TS_ROOT" -mindepth 1 -maxdepth 1 -type d -print0 | sort -z) } # ============================================================================ # Output # ============================================================================ print_report() { local total=$((${#PUBLISHABLE_NO_GIT[@]} + ${#PUBLISHABLE_NO_WORKFLOW[@]} + ${#INTERNAL[@]} + ${#PROPERLY_CONFIGURED[@]})) echo "==============================================" echo " @ts Package Git/Workflow Audit Report" echo "==============================================" echo "" echo "Total packages scanned: $total" echo "" # PUBLISHABLE_NO_GIT (Critical - needs attention) echo "----------------------------------------------" echo "PUBLISHABLE_NO_GIT (${#PUBLISHABLE_NO_GIT[@]} packages)" echo " Packages with _.publish=true but missing .git" echo "----------------------------------------------" if [[ ${#PUBLISHABLE_NO_GIT[@]} -gt 0 ]]; then for pkg in "${PUBLISHABLE_NO_GIT[@]}"; do echo " - $pkg" done else echo " (none)" fi echo "" # PUBLISHABLE_NO_WORKFLOW (Warning - may need attention) echo "----------------------------------------------" echo "PUBLISHABLE_NO_WORKFLOW (${#PUBLISHABLE_NO_WORKFLOW[@]} packages)" echo " Packages with _.publish=true but missing .forgejo/workflows/" echo "----------------------------------------------" if [[ ${#PUBLISHABLE_NO_WORKFLOW[@]} -gt 0 ]]; then for pkg in "${PUBLISHABLE_NO_WORKFLOW[@]}"; do echo " - $pkg" done else echo " (none)" fi echo "" # Only show these in non-quiet mode if [[ "$QUIET_MODE" == false ]]; then # INTERNAL (Informational) echo "----------------------------------------------" echo "INTERNAL (${#INTERNAL[@]} packages)" echo " Packages without _.publish=true (internal/tooling)" echo "----------------------------------------------" if [[ ${#INTERNAL[@]} -gt 0 ]]; then for pkg in "${INTERNAL[@]}"; do echo " - $pkg" done else echo " (none)" fi echo "" # PROPERLY_CONFIGURED (Good) echo "----------------------------------------------" echo "PROPERLY_CONFIGURED (${#PROPERLY_CONFIGURED[@]} packages)" echo " Packages with both .git and .forgejo/workflows/" echo "----------------------------------------------" if [[ ${#PROPERLY_CONFIGURED[@]} -gt 0 ]]; then for pkg in "${PROPERLY_CONFIGURED[@]}"; do echo " - $pkg" done else echo " (none)" fi echo "" fi # Summary echo "==============================================" echo " Summary" echo "==============================================" echo " Properly configured: ${#PROPERLY_CONFIGURED[@]}" echo " Missing git: ${#PUBLISHABLE_NO_GIT[@]}" echo " Missing workflow: ${#PUBLISHABLE_NO_WORKFLOW[@]}" echo " Internal packages: ${#INTERNAL[@]}" echo "" # Exit with error if there are issues if [[ ${#PUBLISHABLE_NO_GIT[@]} -gt 0 || ${#PUBLISHABLE_NO_WORKFLOW[@]} -gt 0 ]]; then return 1 fi return 0 } # ============================================================================ # Main # ============================================================================ main() { if [[ ! -d "$TS_ROOT" ]]; then echo "Error: @ts directory not found at $TS_ROOT" >&2 exit 1 fi audit_packages print_report } main