Skip to content

Commit 963fd35

Browse files
cadamsdotcomclaude
andcommitted
Add missing general-purpose scripts from ApprovIQ
Bring over cleanup_orphaned_e2e.sh (cleans up orphaned Docker resources from interrupted E2E test runs) and extract_supabase_env.sh (already referenced by CI workflow but missing from the repo). Document the cleanup script in the E2E test harness section of how-tests-work.md. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e2bc591 commit 963fd35

3 files changed

Lines changed: 195 additions & 0 deletions

File tree

docs-site/docs/how-tests-work.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,25 @@ If unexpected errors are found, the test suite fails even if all pytest assertio
157157

158158
Setup output (Supabase startup, frontend build, server startup) is captured in a `QuietSetup` buffer. If setup succeeds, none of it is shown. If setup fails, the full captured output is printed for debugging.
159159

160+
### Cleaning Up Orphaned E2E Resources
161+
162+
Each E2E run creates an isolated Supabase instance with its own Docker containers, volumes, and networks. If a run is interrupted (Ctrl-C, crash, timeout), these resources can be left behind. Over time, stale volumes and containers from past runs can accumulate and cause E2E tests to start failing unexpectedly — typically with port conflicts, Supabase startup errors, or database state issues. If E2E tests begin failing and the cause isn't obvious, orphaned resources from previous runs are a likely culprit.
163+
164+
Run the cleanup script to remove them:
165+
166+
```bash
167+
bash scripts/cleanup_orphaned_e2e.sh
168+
```
169+
170+
The script targets only E2E test resources and is safe to run at any time. It cleans up:
171+
172+
- **E2E containers** — Docker containers with `_e2e-` in their name
173+
- **Random-named Supabase containers** — Exited containers from `public.ecr.aws/supabase/` images that aren't part of a named project
174+
- **E2E volumes** — Docker volumes with `_e2e-` in their name
175+
- **Dangling Supabase volumes** — Volumes prefixed with `supabase_` not referenced by any container
176+
- **E2E networks** — Docker networks with `_e2e-` in their name
177+
- **Temporary directories** — Contents of `/tmp/supabase-e2e/`
178+
160179
## Dot Silencing
161180

162181
The `pytest_report_teststatus` hook in [`conftest.py`](https://github.com/cadamsdotcom/CodeLeash/blob/main/tests/conftest.py) suppresses the default progress dots for passing tests:

scripts/cleanup_orphaned_e2e.sh

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#!/bin/bash
2+
# Cleanup orphaned e2e test Supabase instances
3+
# Use this if e2e tests are interrupted and leave behind containers/directories
4+
#
5+
# E2E tests create Supabase instances with project IDs like: e2e-{timestamp}-{8char_random}
6+
# This creates Docker resources named: supabase_{service}_e2e-{timestamp}-{random}
7+
# Interrupted tests may also leave behind:
8+
# - Random-named containers from supabase images (e.g. happy_lumiere)
9+
# - Dangling supabase volumes from incomplete cleanup
10+
11+
set -e
12+
13+
echo "🧹 Cleaning up orphaned E2E Supabase instances..."
14+
15+
# Stop and remove e2e-named Supabase containers
16+
echo ""
17+
echo "🐳 Stopping orphaned E2E containers..."
18+
CONTAINERS=$(docker ps -a --format "{{.Names}}" | grep "_e2e-" 2>/dev/null || true)
19+
20+
if [ -z "$CONTAINERS" ]; then
21+
echo " No orphaned e2e containers found"
22+
else
23+
CONTAINER_COUNT=$(echo "$CONTAINERS" | wc -l | tr -d ' ')
24+
echo " Found $CONTAINER_COUNT orphaned e2e containers:"
25+
echo "$CONTAINERS" | sed 's/^/ - /'
26+
echo "$CONTAINERS" | xargs docker rm -f
27+
echo " ✅ E2E containers removed"
28+
fi
29+
30+
# Remove random-named exited containers from supabase images (orphaned from failed cleanup)
31+
echo ""
32+
echo "🐳 Checking for orphaned random-named Supabase containers..."
33+
# Find exited containers using supabase images that aren't part of a named project.
34+
# Uses image filter to find supabase containers, then excludes known dev instances.
35+
RANDOM_CONTAINERS=""
36+
while IFS=$'\t' read -r name image; do
37+
# Skip containers that belong to a named supabase project (dev or e2e)
38+
if echo "$name" | grep -qE "^supabase_"; then
39+
continue
40+
fi
41+
# This is a random-named container using a supabase image
42+
if [ -z "$RANDOM_CONTAINERS" ]; then
43+
RANDOM_CONTAINERS="$name"
44+
else
45+
RANDOM_CONTAINERS="$RANDOM_CONTAINERS
46+
$name"
47+
fi
48+
done < <(docker ps -a --filter "status=exited" --format "{{.Names}}\t{{.Image}}" \
49+
| grep "public.ecr.aws/supabase/" 2>/dev/null || true)
50+
51+
if [ -z "$RANDOM_CONTAINERS" ]; then
52+
echo " No orphaned random-named containers found"
53+
else
54+
RANDOM_COUNT=$(echo "$RANDOM_CONTAINERS" | wc -l | tr -d ' ')
55+
echo " Found $RANDOM_COUNT orphaned random-named Supabase containers:"
56+
echo "$RANDOM_CONTAINERS" | sed 's/^/ - /'
57+
echo "$RANDOM_CONTAINERS" | xargs docker rm
58+
echo " ✅ Random-named containers removed"
59+
fi
60+
61+
# Remove orphaned e2e Docker volumes
62+
echo ""
63+
echo "📦 Removing orphaned E2E Docker volumes..."
64+
E2E_VOLUMES=$(docker volume ls -q | grep "_e2e-" 2>/dev/null || true)
65+
66+
if [ -z "$E2E_VOLUMES" ]; then
67+
echo " No orphaned e2e volumes found"
68+
else
69+
VOLUME_COUNT=$(echo "$E2E_VOLUMES" | wc -l | tr -d ' ')
70+
echo " Found $VOLUME_COUNT orphaned e2e volumes"
71+
echo "$E2E_VOLUMES" | xargs docker volume rm 2>/dev/null || true
72+
echo " ✅ E2E volumes removed"
73+
fi
74+
75+
# Remove dangling supabase volumes (not referenced by any container)
76+
echo ""
77+
echo "📦 Checking for dangling Supabase volumes..."
78+
DANGLING_VOLUMES=$(docker volume ls -q --filter "dangling=true" | grep "^supabase_" 2>/dev/null || true)
79+
80+
if [ -z "$DANGLING_VOLUMES" ]; then
81+
echo " No dangling Supabase volumes found"
82+
else
83+
DANGLING_COUNT=$(echo "$DANGLING_VOLUMES" | wc -l | tr -d ' ')
84+
echo " Found $DANGLING_COUNT dangling Supabase volumes:"
85+
echo "$DANGLING_VOLUMES" | sed 's/^/ - /'
86+
echo "$DANGLING_VOLUMES" | xargs docker volume rm 2>/dev/null || true
87+
echo " ✅ Dangling volumes removed"
88+
fi
89+
90+
# Remove e2e Docker networks (not a blanket prune - only targets e2e networks)
91+
echo ""
92+
echo "🌐 Removing orphaned E2E networks..."
93+
NETWORKS=$(docker network ls --format "{{.Name}}" | grep "_e2e-" 2>/dev/null || true)
94+
95+
if [ -z "$NETWORKS" ]; then
96+
echo " No orphaned e2e networks found"
97+
else
98+
echo " Found orphaned e2e networks:"
99+
echo "$NETWORKS" | sed 's/^/ - /'
100+
echo "$NETWORKS" | xargs docker network rm 2>/dev/null || true
101+
echo " ✅ E2E networks removed"
102+
fi
103+
104+
# Remove temporary directories
105+
echo ""
106+
echo "🗑️ Removing temporary directories..."
107+
TEMP_DIR="/tmp/supabase-e2e"
108+
109+
if [ ! -d "$TEMP_DIR" ]; then
110+
echo " No temporary directories found"
111+
elif [ -z "$(ls -A "$TEMP_DIR" 2>/dev/null)" ]; then
112+
echo " Temporary directory is empty"
113+
else
114+
echo " Found temporary directories:"
115+
ls -1 "$TEMP_DIR" | sed 's/^/ - /'
116+
rm -rf "${TEMP_DIR:?}"/*
117+
echo " ✅ Directories removed"
118+
fi
119+
120+
# Show disk space reclaimed
121+
echo ""
122+
echo "💾 Docker disk usage after cleanup:"
123+
docker system df
124+
125+
echo ""
126+
echo "✨ Cleanup complete!"

scripts/extract_supabase_env.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/bin/bash
2+
# Extract Supabase environment variables from local instance
3+
# Usage: source scripts/extract_supabase_env.sh
4+
5+
set -e
6+
7+
# Check if Supabase is running
8+
if ! command -v supabase &> /dev/null; then
9+
echo "❌ Supabase CLI not found. Please install Supabase CLI first."
10+
exit 1
11+
fi
12+
13+
# Get Supabase status
14+
echo "🔍 Extracting Supabase environment variables..."
15+
STATUS_OUTPUT=$(supabase status -o env)
16+
17+
if [ -z "$STATUS_OUTPUT" ]; then
18+
echo "❌ Failed to get Supabase status. Is Supabase running?"
19+
exit 1
20+
fi
21+
22+
# Extract and export environment variables
23+
export SUPABASE_URL=$(echo "$STATUS_OUTPUT" | grep -E '^API_URL=' | cut -d'=' -f2- | tr -d '"')
24+
export SUPABASE_ANON_KEY=$(echo "$STATUS_OUTPUT" | grep -E '^ANON_KEY=' | cut -d'=' -f2- | tr -d '"')
25+
export SUPABASE_SERVICE_KEY=$(echo "$STATUS_OUTPUT" | grep -E '^SERVICE_ROLE_KEY=' | cut -d'=' -f2- | tr -d '"')
26+
export DATABASE_URL=$(echo "$STATUS_OUTPUT" | grep -E '^DB_URL=' | cut -d'=' -f2- | tr -d '"')
27+
export JWT_SECRET_KEY=$(echo "$STATUS_OUTPUT" | grep -E '^JWT_SECRET=' | cut -d'=' -f2- | tr -d '"')
28+
29+
# Validate that all required variables were extracted
30+
required_vars=("SUPABASE_URL" "SUPABASE_ANON_KEY" "SUPABASE_SERVICE_KEY" "DATABASE_URL" "JWT_SECRET_KEY")
31+
missing_vars=()
32+
33+
for var in "${required_vars[@]}"; do
34+
if [ -z "${!var}" ]; then
35+
missing_vars+=("$var")
36+
fi
37+
done
38+
39+
if [ ${#missing_vars[@]} -gt 0 ]; then
40+
echo "❌ Failed to extract required environment variables: ${missing_vars[*]}"
41+
echo "Raw Supabase status output:"
42+
echo "$STATUS_OUTPUT"
43+
exit 1
44+
fi
45+
46+
# Success - log the extracted configuration
47+
echo "✅ Successfully extracted Supabase environment variables:"
48+
echo " API URL: $SUPABASE_URL"
49+
echo " DB URL: $DATABASE_URL"
50+
echo " All authentication keys extracted successfully"

0 commit comments

Comments
 (0)