feat(dev-env): shell scripts (git-hooks, worktree, deploy, regtest, nav) and smoke test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
7960f82494
commit
dbd9e76027
13 changed files with 2496 additions and 0 deletions
142
modules/dev-env/scripts/status.sh
Normal file
142
modules/dev-env/scripts/status.sh
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
#!/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
|
||||
Loading…
Add table
Add a link
Reference in a new issue