Skip to content

Commit c7d50f6

Browse files
authored
fix(homeboy): attach DMC primaries as project components (#99)
1 parent dba1db2 commit c7d50f6

2 files changed

Lines changed: 220 additions & 2 deletions

File tree

lib/data-machine.sh

Lines changed: 121 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,19 +69,138 @@ create_dm_agent() {
6969
}
7070

7171
sync_homeboy_availability() {
72+
local homeboy_available=false
73+
74+
if command -v homeboy >/dev/null 2>&1; then
75+
homeboy_available=true
76+
fi
77+
7278
if [ "$DRY_RUN" = true ]; then
73-
if command -v homeboy >/dev/null 2>&1; then
79+
if [ "$homeboy_available" = true ]; then
7480
echo -e "${BLUE}[dry-run]${NC} $WP_CMD option update datamachine_code_homeboy_available 1"
7581
else
7682
echo -e "${BLUE}[dry-run]${NC} $WP_CMD option delete datamachine_code_homeboy_available"
7783
fi
84+
sync_homeboy_project_components
7885
return 0
7986
fi
8087

81-
if command -v homeboy >/dev/null 2>&1; then
88+
if [ "$homeboy_available" = true ]; then
8289
wp_cmd option update datamachine_code_homeboy_available 1 >/dev/null 2>&1 || \
8390
warn "Could not record Homeboy availability for AGENTS.md compose"
91+
sync_homeboy_project_components
8492
else
8593
wp_cmd option delete datamachine_code_homeboy_available >/dev/null 2>&1 || true
8694
fi
8795
}
96+
97+
discover_dm_workspace_dir() {
98+
if [ -n "${DATAMACHINE_WORKSPACE_PATH:-}" ]; then
99+
DM_WORKSPACE_DIR="$DATAMACHINE_WORKSPACE_PATH"
100+
return 0
101+
fi
102+
103+
if [ "${DRY_RUN:-false}" = true ] || [ -z "${SITE_PATH:-}" ] || [ ! -f "$SITE_PATH/wp-config.php" ]; then
104+
return 0
105+
fi
106+
107+
local workspace_path
108+
workspace_path=$(wp_cmd datamachine-code workspace path 2>/dev/null || true)
109+
if [ -n "$workspace_path" ]; then
110+
DM_WORKSPACE_DIR="$workspace_path"
111+
fi
112+
}
113+
114+
homeboy_project_id() {
115+
if [ -n "${HOMEBOY_PROJECT_ID:-}" ]; then
116+
printf '%s\n' "$HOMEBOY_PROJECT_ID"
117+
return 0
118+
fi
119+
120+
if [ -z "${SITE_PATH:-}" ] || [ ! -f "$SITE_PATH/homeboy.json" ]; then
121+
return 1
122+
fi
123+
124+
python3 - "$SITE_PATH/homeboy.json" <<'PY'
125+
import json
126+
import sys
127+
128+
with open(sys.argv[1], encoding="utf-8") as handle:
129+
project_id = json.load(handle).get("id", "")
130+
131+
if project_id:
132+
print(project_id)
133+
PY
134+
}
135+
136+
sync_homeboy_project_components() {
137+
if ! command -v homeboy >/dev/null 2>&1; then
138+
return 0
139+
fi
140+
141+
discover_dm_workspace_dir
142+
143+
local project_id
144+
if ! project_id=$(homeboy_project_id); then
145+
warn "Homeboy project config not found at site root — skipping DMC component attachment"
146+
return 0
147+
fi
148+
149+
if [ -z "${DM_WORKSPACE_DIR:-}" ]; then
150+
warn "DMC workspace path not configured — skipping Homeboy component attachment"
151+
return 0
152+
fi
153+
154+
if [ ! -d "$DM_WORKSPACE_DIR" ]; then
155+
warn "DMC workspace path does not exist ($DM_WORKSPACE_DIR) — skipping Homeboy component attachment"
156+
return 0
157+
fi
158+
159+
log "Attaching Homeboy components from DMC workspace: $DM_WORKSPACE_DIR"
160+
161+
local attached=0
162+
local skipped=0
163+
local failed=0
164+
local repo_path repo_name
165+
166+
shopt -s nullglob
167+
for repo_path in "$DM_WORKSPACE_DIR"/*; do
168+
[ -d "$repo_path" ] || continue
169+
repo_name=$(basename "$repo_path")
170+
171+
if [ -n "${SITE_PATH:-}" ] && [ "$repo_path" = "$SITE_PATH" ]; then
172+
log " skipped $repo_name: site project root"
173+
skipped=$((skipped + 1))
174+
continue
175+
fi
176+
177+
if [[ "$repo_name" == *"@"* ]]; then
178+
log " skipped $repo_name: worktree skipped"
179+
skipped=$((skipped + 1))
180+
continue
181+
fi
182+
183+
if [ ! -f "$repo_path/homeboy.json" ]; then
184+
log " skipped $repo_name: no homeboy.json"
185+
skipped=$((skipped + 1))
186+
continue
187+
fi
188+
189+
if [ "${DRY_RUN:-false}" = true ]; then
190+
echo -e "${BLUE}[dry-run]${NC} homeboy project components attach-path $project_id $repo_path"
191+
attached=$((attached + 1))
192+
continue
193+
fi
194+
195+
if homeboy project components attach-path "$project_id" "$repo_path" >/dev/null; then
196+
log " attached $repo_name"
197+
attached=$((attached + 1))
198+
else
199+
warn " failed $repo_name: homeboy attach-path failed"
200+
failed=$((failed + 1))
201+
fi
202+
done
203+
shopt -u nullglob
204+
205+
log "Homeboy component sync complete: $attached attached, $skipped skipped, $failed failed"
206+
}

tests/homeboy-components.sh

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#!/bin/bash
2+
# tests/homeboy-components.sh — unit test for DMC workspace Homeboy component attachment.
3+
set -eu
4+
5+
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
6+
7+
# shellcheck disable=SC1091
8+
source "$SCRIPT_DIR/lib/common.sh"
9+
# shellcheck disable=SC1091
10+
source "$SCRIPT_DIR/lib/data-machine.sh"
11+
12+
TMP="$(mktemp -d)"
13+
trap 'rm -rf "$TMP"' EXIT
14+
15+
SITE_PATH="$TMP/site"
16+
DM_WORKSPACE_DIR="$TMP/workspace"
17+
WP_CMD="wp"
18+
DRY_RUN=false
19+
mkdir -p "$SITE_PATH" "$DM_WORKSPACE_DIR"
20+
21+
cat > "$SITE_PATH/homeboy.json" <<'JSON'
22+
{"id":"site-project"}
23+
JSON
24+
25+
mkdir -p \
26+
"$DM_WORKSPACE_DIR/alpha" \
27+
"$DM_WORKSPACE_DIR/beta" \
28+
"$DM_WORKSPACE_DIR/alpha@feature" \
29+
"$DM_WORKSPACE_DIR/no-metadata"
30+
31+
cat > "$DM_WORKSPACE_DIR/alpha/homeboy.json" <<'JSON'
32+
{"id":"alpha"}
33+
JSON
34+
cat > "$DM_WORKSPACE_DIR/beta/homeboy.json" <<'JSON'
35+
{"id":"beta"}
36+
JSON
37+
cat > "$DM_WORKSPACE_DIR/alpha@feature/homeboy.json" <<'JSON'
38+
{"id":"alpha-feature"}
39+
JSON
40+
41+
FAKE_BIN="$TMP/bin"
42+
mkdir -p "$FAKE_BIN"
43+
cat > "$FAKE_BIN/homeboy" <<'SH'
44+
#!/bin/sh
45+
if [ "$1 $2 $3" = "project components attach-path" ]; then
46+
printf '%s|%s\n' "$4" "$5" >> "$HOMEBOY_ATTACH_LOG"
47+
exit 0
48+
fi
49+
exit 2
50+
SH
51+
chmod +x "$FAKE_BIN/homeboy"
52+
53+
HOMEBOY_ATTACH_LOG="$TMP/attached.log"
54+
export HOMEBOY_ATTACH_LOG
55+
PATH="$FAKE_BIN:$PATH"
56+
57+
assert_contains() {
58+
local needle="$1" file="$2"
59+
if ! grep -qF "$needle" "$file"; then
60+
echo "FAIL: expected '$needle' in $file"
61+
cat "$file"
62+
exit 1
63+
fi
64+
}
65+
66+
assert_not_contains() {
67+
local needle="$1" file="$2"
68+
if grep -qF "$needle" "$file"; then
69+
echo "FAIL: unexpected '$needle' in $file"
70+
cat "$file"
71+
exit 1
72+
fi
73+
}
74+
75+
sync_homeboy_project_components > "$TMP/output.log"
76+
77+
assert_contains "site-project|$DM_WORKSPACE_DIR/alpha" "$HOMEBOY_ATTACH_LOG"
78+
assert_contains "site-project|$DM_WORKSPACE_DIR/beta" "$HOMEBOY_ATTACH_LOG"
79+
assert_not_contains "alpha@feature" "$HOMEBOY_ATTACH_LOG"
80+
assert_not_contains "no-metadata" "$HOMEBOY_ATTACH_LOG"
81+
82+
assert_contains "skipped alpha@feature: worktree skipped" "$TMP/output.log"
83+
assert_contains "skipped no-metadata: no homeboy.json" "$TMP/output.log"
84+
assert_contains "Homeboy component sync complete: 2 attached, 2 skipped, 0 failed" "$TMP/output.log"
85+
86+
DRY_RUN=true
87+
HOMEBOY_ATTACH_LOG="$TMP/dry-run-attached.log"
88+
export HOMEBOY_ATTACH_LOG
89+
sync_homeboy_project_components > "$TMP/dry-run-output.log"
90+
91+
if [ -f "$HOMEBOY_ATTACH_LOG" ]; then
92+
echo "FAIL: dry-run should not call homeboy attach-path"
93+
cat "$HOMEBOY_ATTACH_LOG"
94+
exit 1
95+
fi
96+
assert_contains "homeboy project components attach-path site-project $DM_WORKSPACE_DIR/alpha" "$TMP/dry-run-output.log"
97+
assert_contains "homeboy project components attach-path site-project $DM_WORKSPACE_DIR/beta" "$TMP/dry-run-output.log"
98+
99+
echo "OK: Homeboy component attachment skips worktrees and metadata-less repos"

0 commit comments

Comments
 (0)