Structure: - publishing/ - version bumping and registry publishing - git/ - multi-repo git operations - config/ - package configuration utilities - lint/ - ESLint and code quality scripts - forgejo/ - Forgejo CI/CD automation (primary) - gitlab/ - DEPRECATED legacy GitLab scripts - migration/ - one-time migration utilities - templates/ - CI/CD template files - analysis/ - codebase analysis scripts - oneoffs/ - uncategorized one-time scripts Note: commits CLI will be merged into @ml/auto-commit-service Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
99 lines
2.5 KiB
Bash
Executable file
99 lines
2.5 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# git-repo-status.sh - Find all git repos and show their status
|
|
#
|
|
# Usage:
|
|
# git-repo-status.sh [options] [root_path]
|
|
# git-repo-status.sh # defaults to current directory
|
|
# git-repo-status.sh ~/Code/@packages # search specific path
|
|
# git-repo-status.sh --dirty # only show repos with changes
|
|
# git-repo-status.sh --dirty ~/Code # combine options
|
|
#
|
|
# Options:
|
|
# --dirty, -d Only show repositories with uncommitted changes
|
|
# --help, -h Show this help message
|
|
#
|
|
# Output:
|
|
# Lists all git repos with uncommitted changes, showing:
|
|
# - Repository path
|
|
# - Package name (if package.json exists)
|
|
# - Number of changed files
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
DIRTY_ONLY=false
|
|
ROOT_PATH="."
|
|
|
|
# Parse arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--dirty|-d)
|
|
DIRTY_ONLY=true
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
head -25 "$0" | tail -20
|
|
exit 0
|
|
;;
|
|
*)
|
|
ROOT_PATH="$1"
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Find all git repos
|
|
repos=$(find "$ROOT_PATH" -name ".git" -type d 2>/dev/null | while read gitdir; do
|
|
dirname "$gitdir"
|
|
done | sort)
|
|
|
|
if [ -z "$repos" ]; then
|
|
echo "No git repositories found in $ROOT_PATH"
|
|
exit 0
|
|
fi
|
|
|
|
# Header
|
|
printf "${BLUE}%-50s %-35s %s${NC}\n" "PATH" "PACKAGE" "CHANGES"
|
|
printf "%-50s %-35s %s\n" "$(printf '%.0s-' {1..50})" "$(printf '%.0s-' {1..35})" "-------"
|
|
|
|
dirty_count=0
|
|
clean_count=0
|
|
|
|
echo "$repos" | while read repo; do
|
|
# Get change count
|
|
changes=$(git -C "$repo" status --porcelain 2>/dev/null | wc -l)
|
|
|
|
# Get package name if exists
|
|
if [ -f "$repo/package.json" ]; then
|
|
pkg_name=$(python3 -c "import json; print(json.load(open('$repo/package.json')).get('name', '-'))" 2>/dev/null || echo "-")
|
|
else
|
|
pkg_name="-"
|
|
fi
|
|
|
|
# Relative path for cleaner output
|
|
rel_path="${repo#$ROOT_PATH/}"
|
|
[ "$rel_path" = "$repo" ] && rel_path="$repo"
|
|
|
|
if [ "$changes" -gt 0 ]; then
|
|
printf "${YELLOW}%-50s${NC} %-35s ${RED}%d${NC}\n" "$rel_path" "$pkg_name" "$changes"
|
|
elif [ "$DIRTY_ONLY" = false ]; then
|
|
printf "${GREEN}%-50s${NC} %-35s ${GREEN}✓${NC}\n" "$rel_path" "$pkg_name"
|
|
fi
|
|
done
|
|
|
|
# Summary
|
|
echo ""
|
|
total=$(echo "$repos" | wc -l)
|
|
dirty=$(echo "$repos" | while read repo; do
|
|
git -C "$repo" status --porcelain 2>/dev/null | wc -l
|
|
done | awk '$1 > 0' | wc -l)
|
|
|
|
echo -e "${BLUE}Summary:${NC} $total repos, ${RED}$dirty dirty${NC}, ${GREEN}$((total - dirty)) clean${NC}"
|