142 lines
4.8 KiB
Bash
142 lines
4.8 KiB
Bash
#!/usr/bin/env bash
|
|
# dev-status: show divergence and dirty state of every dev-env worktree
|
|
#
|
|
# Replaces ~/omarchy-dev-env/setup/dev-status.sh, which referenced a
|
|
# stale $PROJECTS_DIR layout. This version reads /etc/dev-env/projects.json
|
|
# and walks the actual declared worktrees.
|
|
|
|
set -euo pipefail
|
|
|
|
if [[ -r /etc/dev-env/config.sh ]]; then
|
|
# shellcheck disable=SC1091
|
|
source /etc/dev-env/config.sh
|
|
fi
|
|
|
|
PROJECTS_JSON="${DEVENV_PROJECTS_JSON:-/etc/dev-env/projects.json}"
|
|
|
|
if [[ ! -r "$PROJECTS_JSON" ]]; then
|
|
echo "projects.json not found at $PROJECTS_JSON" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq >/dev/null; then
|
|
echo "jq required" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Colors — shared palette (RED/GREEN/YELLOW/BLUE/CYAN/BOLD/NC …)
|
|
if [[ -r /etc/dev-env/lib-colors.sh ]]; then
|
|
# shellcheck disable=SC1091
|
|
source /etc/dev-env/lib-colors.sh
|
|
fi
|
|
|
|
issues=()
|
|
|
|
header() {
|
|
echo ""
|
|
echo -e "${BOLD}${CYAN}═══════════════════════════════════════════════════════${NC}"
|
|
echo -e "${BOLD}${CYAN} $1${NC}"
|
|
echo -e "${BOLD}${CYAN}═══════════════════════════════════════════════════════${NC}"
|
|
}
|
|
|
|
check_one() {
|
|
local label="$1" path="$2" has_upstream="${3:-false}"
|
|
|
|
if [[ ! -d "$path/.git" ]] && [[ ! -f "$path/.git" ]]; then
|
|
printf " ${YELLOW}⚠${NC} %s: not present\n" "$label"
|
|
issues+=("$label: not present")
|
|
return
|
|
fi
|
|
|
|
git -C "$path" fetch --all --quiet 2>/dev/null || true
|
|
|
|
local branch icons="" status_str=""
|
|
branch="$(git -C "$path" branch --show-current 2>/dev/null || echo '?')"
|
|
|
|
[[ -n "$(git -C "$path" status --porcelain)" ]] && {
|
|
icons+="${YELLOW}●${NC} "
|
|
status_str+="dirty "
|
|
}
|
|
|
|
local behind ahead
|
|
behind=$(git -C "$path" rev-list --count "HEAD..origin/$branch" 2>/dev/null || echo 0)
|
|
ahead=$(git -C "$path" rev-list --count "origin/$branch..HEAD" 2>/dev/null || echo 0)
|
|
(( behind > 0 )) && icons+="${RED}↓${NC}$behind "
|
|
(( ahead > 0 )) && icons+="${GREEN}↑${NC}$ahead "
|
|
|
|
if [[ "$has_upstream" == "true" ]] && git -C "$path" remote get-url upstream &>/dev/null; then
|
|
local ub="main"
|
|
git -C "$path" rev-parse upstream/main &>/dev/null || ub="master"
|
|
local ub_behind
|
|
ub_behind=$(git -C "$path" rev-list --count "HEAD..upstream/$ub" 2>/dev/null || echo 0)
|
|
if (( ub_behind > 0 )); then
|
|
icons+="${CYAN}⇣${NC}$ub_behind "
|
|
issues+=("$label: $ub_behind behind upstream/$ub")
|
|
fi
|
|
fi
|
|
|
|
[[ -z "$icons" ]] && icons="${GREEN}✓${NC}"
|
|
printf " %-45s %s (%s)\n" "$label" "$icons" "$branch"
|
|
}
|
|
|
|
header "Development Environment Status"
|
|
echo -e " ${BLUE}Date:${NC} $(date '+%Y-%m-%d %H:%M')"
|
|
echo -e " ${BLUE}Host:${NC} $(hostname)"
|
|
echo -e " ${BLUE}Root:${NC} ${DEV_ROOT:-?}"
|
|
|
|
# Walk every project and worktree from the JSON.
|
|
mapfile -t PROJECTS < <(jq -r 'keys[]' "$PROJECTS_JSON")
|
|
|
|
for proj in "${PROJECTS[@]}"; do
|
|
echo ""
|
|
echo -e "${BLUE}─── $proj ───${NC}"
|
|
|
|
is_clone="$(jq -r --arg p "$proj" '.[$p].isClone' "$PROJECTS_JSON")"
|
|
has_upstream_decl="$(jq -r --arg p "$proj" '.[$p].remotes.upstream != null' "$PROJECTS_JSON")"
|
|
|
|
if [[ "$is_clone" == "true" ]]; then
|
|
clone_path="$(jq -r --arg p "$proj" '.[$p].clonePath' "$PROJECTS_JSON")"
|
|
check_one "$proj" "$clone_path" "$has_upstream_decl"
|
|
else
|
|
while IFS=$'\t' read -r wt_name wt_path; do
|
|
[[ -z "$wt_name" || "$wt_path" == "null" ]] && continue
|
|
check_one "$proj/$wt_name" "$wt_path" "$has_upstream_decl"
|
|
done < <(jq -r --arg p "$proj" '
|
|
.[$p].worktrees
|
|
| to_entries[]
|
|
| "\(.key)\t\(.value.path)"
|
|
' "$PROJECTS_JSON")
|
|
fi
|
|
done
|
|
|
|
# Docker
|
|
echo ""
|
|
echo -e "${BLUE}─── Docker ───${NC}"
|
|
if command -v docker &>/dev/null; then
|
|
running="$(docker ps --format '{{.Names}}' 2>/dev/null | wc -l)"
|
|
echo -e " ${BLUE}Containers running:${NC} $running"
|
|
fi
|
|
|
|
header "Summary"
|
|
if (( ${#issues[@]} == 0 )); then
|
|
echo -e " ${GREEN}✓ All worktrees are clean and in sync!${NC}"
|
|
else
|
|
echo -e " ${YELLOW}Issues found:${NC}"
|
|
for issue in "${issues[@]}"; do
|
|
echo -e " ${YELLOW}•${NC} $issue"
|
|
done
|
|
fi
|
|
|
|
cat <<EOF
|
|
|
|
${BLUE}Legend:${NC}
|
|
${GREEN}✓${NC} clean ${YELLOW}●${NC} dirty ${GREEN}↑${NC} ahead origin
|
|
${RED}↓${NC} behind origin ${CYAN}⇣${NC} behind upstream
|
|
|
|
${BLUE}Quick actions:${NC}
|
|
wts sync all worktrees with origin
|
|
wtu <repo> fetch upstream + show divergence
|
|
rebase status which forks need rebasing onto upstream
|
|
dev-env-bootstrap materialize missing worktrees
|
|
|
|
EOF
|