Skip to content

Commit ee42c59

Browse files
authored
Merge branch 'main' into feat/claude-desktop
2 parents d5a1683 + 36d245f commit ee42c59

4 files changed

Lines changed: 197 additions & 0 deletions

File tree

.githooks/pre-commit

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
exec "$(git rev-parse --show-toplevel)/scripts/check-bun-locks.sh"

scripts/check-bun-locks.sh

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
workspaces=(
5+
"cli"
6+
"control-plane/dashboard-ui"
7+
)
8+
9+
repo_root="$(git rev-parse --show-toplevel)"
10+
staged_files=()
11+
while IFS= read -r staged_file; do
12+
staged_files+=("$staged_file")
13+
done < <(git diff --cached --name-only --diff-filter=ACMR)
14+
15+
if [[ "${#staged_files[@]}" -eq 0 ]]; then
16+
exit 0
17+
fi
18+
19+
needs_check() {
20+
local workspace="$1"
21+
local manifest="$workspace/package.json"
22+
local file
23+
24+
for file in "${staged_files[@]}"; do
25+
if [[ "$file" == "$manifest" ]]; then
26+
return 0
27+
fi
28+
done
29+
30+
return 1
31+
}
32+
33+
check_workspaces=()
34+
for workspace in "${workspaces[@]}"; do
35+
if needs_check "$workspace"; then
36+
check_workspaces+=("$workspace")
37+
fi
38+
done
39+
40+
if [[ "${#check_workspaces[@]}" -eq 0 ]]; then
41+
exit 0
42+
fi
43+
44+
if ! command -v bun >/dev/null 2>&1; then
45+
echo "bun is required to verify lockfile sync before committing." >&2
46+
exit 1
47+
fi
48+
49+
for workspace in "${check_workspaces[@]}"; do
50+
lockfile="$workspace/bun.lock"
51+
before="$(git -C "$repo_root" hash-object "$lockfile")"
52+
53+
echo "Checking $workspace bun.lock"
54+
(cd "$repo_root/$workspace" && bun install --frozen-lockfile)
55+
56+
after="$(git -C "$repo_root" hash-object "$lockfile")"
57+
if [[ "$before" != "$after" ]]; then
58+
echo "$lockfile changed after bun install --frozen-lockfile." >&2
59+
echo "Stage the updated lockfile and commit again." >&2
60+
exit 1
61+
fi
62+
done

scripts/install-git-hooks.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
repo_root="$(git rev-parse --show-toplevel)"
5+
git -C "$repo_root" config core.hooksPath .githooks
6+
echo "Configured git hooks path: .githooks"
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
5+
SCRIPT="$ROOT/scripts/check-bun-locks.sh"
6+
7+
assert_file_contains() {
8+
local file="$1"
9+
local expected="$2"
10+
11+
if ! grep -Fq "$expected" "$file"; then
12+
echo "expected $file to contain: $expected" >&2
13+
echo "actual:" >&2
14+
cat "$file" >&2
15+
exit 1
16+
fi
17+
}
18+
19+
new_repo() {
20+
local dir
21+
dir="$(mktemp -d)"
22+
23+
git -C "$dir" init -q
24+
git -C "$dir" config user.email test@example.com
25+
git -C "$dir" config user.name "Test User"
26+
27+
mkdir -p "$dir/cli" "$dir/control-plane/dashboard-ui"
28+
printf '{"dependencies":{"left-pad":"1.0.0"}}\n' > "$dir/cli/package.json"
29+
printf 'lock\n' > "$dir/cli/bun.lock"
30+
printf '{"dependencies":{"react":"19.0.0"}}\n' > "$dir/control-plane/dashboard-ui/package.json"
31+
printf 'lock\n' > "$dir/control-plane/dashboard-ui/bun.lock"
32+
git -C "$dir" add .
33+
git -C "$dir" commit -qm "initial"
34+
35+
printf '%s\n' "$dir"
36+
}
37+
38+
with_fake_bun() {
39+
local bin_dir="$1"
40+
local log_file="$2"
41+
local mode="${3:-clean}"
42+
43+
mkdir -p "$bin_dir"
44+
cat > "$bin_dir/bun" <<'BUN'
45+
#!/usr/bin/env bash
46+
set -euo pipefail
47+
48+
printf '%s|%s\n' "$PWD" "$*" >> "$FAKE_BUN_LOG"
49+
50+
if [[ "${FAKE_BUN_MODE:-clean}" == "dirty-lock" ]]; then
51+
printf 'changed by fake bun\n' >> bun.lock
52+
fi
53+
BUN
54+
chmod +x "$bin_dir/bun"
55+
56+
export PATH="$bin_dir:$PATH"
57+
export FAKE_BUN_LOG="$log_file"
58+
export FAKE_BUN_MODE="$mode"
59+
}
60+
61+
test_skips_when_no_package_manifest_is_staged() {
62+
local repo bin_dir log_file
63+
repo="$(new_repo)"
64+
bin_dir="$(mktemp -d)"
65+
log_file="$repo/bun.log"
66+
with_fake_bun "$bin_dir" "$log_file"
67+
68+
printf 'docs\n' > "$repo/README.md"
69+
git -C "$repo" add README.md
70+
71+
(cd "$repo" && "$SCRIPT")
72+
if [[ -e "$log_file" ]]; then
73+
echo "expected bun not to run for unrelated staged files" >&2
74+
cat "$log_file" >&2
75+
exit 1
76+
fi
77+
}
78+
79+
test_skips_unrelated_staged_files_without_bun() {
80+
local repo
81+
repo="$(new_repo)"
82+
83+
printf 'docs\n' > "$repo/README.md"
84+
git -C "$repo" add README.md
85+
86+
(cd "$repo" && PATH="/usr/bin:/bin" "$SCRIPT")
87+
}
88+
89+
test_checks_each_staged_manifest_workspace() {
90+
local repo bin_dir log_file
91+
repo="$(new_repo)"
92+
bin_dir="$(mktemp -d)"
93+
log_file="$repo/bun.log"
94+
with_fake_bun "$bin_dir" "$log_file"
95+
96+
printf '{"dependencies":{"left-pad":"1.0.1"}}\n' > "$repo/cli/package.json"
97+
git -C "$repo" add cli/package.json
98+
99+
(cd "$repo" && "$SCRIPT")
100+
assert_file_contains "$log_file" "$repo/cli|install --frozen-lockfile"
101+
}
102+
103+
test_fails_when_bun_changes_lockfile() {
104+
local repo bin_dir log_file output
105+
repo="$(new_repo)"
106+
bin_dir="$(mktemp -d)"
107+
log_file="$repo/bun.log"
108+
output="$repo/output.log"
109+
with_fake_bun "$bin_dir" "$log_file" "dirty-lock"
110+
111+
printf '{"dependencies":{"left-pad":"1.0.2"}}\n' > "$repo/cli/package.json"
112+
git -C "$repo" add cli/package.json
113+
114+
if (cd "$repo" && "$SCRIPT") > "$output" 2>&1; then
115+
echo "expected hook check to fail when bun.lock changes" >&2
116+
exit 1
117+
fi
118+
119+
assert_file_contains "$output" "cli/bun.lock changed after bun install --frozen-lockfile"
120+
}
121+
122+
test_skips_when_no_package_manifest_is_staged
123+
test_skips_unrelated_staged_files_without_bun
124+
test_checks_each_staged_manifest_workspace
125+
test_fails_when_bun_changes_lockfile

0 commit comments

Comments
 (0)