docs: add git worktree isolation section
Document the critical requirement to set COMPOSE_PROJECT_NAME for
worktree isolation:
- Problem: Without COMPOSE_PROJECT_NAME, all worktrees share image
names (e.g., test-price-db:latest) causing build conflicts
- Solution: export COMPOSE_PROJECT_NAME="test-${TEST_INSTANCE_ID}"
- Cleanup scoping: Only remove containers for current branch
Also updated:
- Common Mistakes table with new isolation pitfalls
- Service Test Script Template with COMPOSE_PROJECT_NAME export
This commit is contained in:
58
SKILL.md
58
SKILL.md
@@ -192,6 +192,59 @@ export TEST_API_URL="http://localhost:${API_PORT}"
|
|||||||
export TEST_DATABASE_URL="postgresql://test:test@localhost:${DB_PORT}/testdb"
|
export TEST_DATABASE_URL="postgresql://test:test@localhost:${DB_PORT}/testdb"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Git Worktree Isolation
|
||||||
|
|
||||||
|
When using git worktrees for parallel feature development, additional isolation is required beyond container and network naming.
|
||||||
|
|
||||||
|
**Problem**: Without `COMPOSE_PROJECT_NAME`, Docker Compose uses the directory name as the project name. Since all test directories are typically named `test`, all worktrees share the same image names (e.g., `test-price-db:latest`). When worktree A builds while worktree B is testing, B's containers can fail due to image conflicts.
|
||||||
|
|
||||||
|
**Solution**: Set `COMPOSE_PROJECT_NAME` to include the instance ID:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# scripts/test-service.sh
|
||||||
|
TEST_INSTANCE_ID=$(./scripts/get-test-instance-id.sh)
|
||||||
|
export TEST_INSTANCE_ID
|
||||||
|
|
||||||
|
# CRITICAL: Isolate Docker images between worktrees
|
||||||
|
# Without this, all worktrees share image names like "test-price-db:latest"
|
||||||
|
export COMPOSE_PROJECT_NAME="test-${TEST_INSTANCE_ID}"
|
||||||
|
|
||||||
|
cd "services/${SERVICE}/deploy/test"
|
||||||
|
docker compose up -d --build --wait
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**: Each worktree gets unique image names:
|
||||||
|
- `test-feature-auth-price-db:latest` (worktree on feature/auth)
|
||||||
|
- `test-feature-api-price-db:latest` (worktree on feature/api)
|
||||||
|
- `test-main-price-db:latest` (main branch)
|
||||||
|
|
||||||
|
**What gets isolated with full implementation**:
|
||||||
|
|
||||||
|
| Resource | Isolation Variable | Example |
|
||||||
|
|----------|-------------------|---------|
|
||||||
|
| Container names | `container_name: mydb-test-${TEST_INSTANCE_ID}` | `mydb-test-feature-auth` |
|
||||||
|
| Network names | `name: myproject-test-${TEST_INSTANCE_ID}` | `myproject-test-feature-auth` |
|
||||||
|
| Image names | `COMPOSE_PROJECT_NAME=test-${TEST_INSTANCE_ID}` | `test-feature-auth-mydb:latest` |
|
||||||
|
|
||||||
|
### Cleanup Command Scoping
|
||||||
|
|
||||||
|
**Problem**: A global `test-clean-all` command that removes all containers matching `name=test-` will interfere with tests running in other worktrees.
|
||||||
|
|
||||||
|
**Solution**: Scope cleanup to the current branch's instance ID:
|
||||||
|
|
||||||
|
```makefile
|
||||||
|
# BAD: Removes ALL test containers across all branches
|
||||||
|
test-clean-all:
|
||||||
|
@docker ps -a --filter "name=test-" --format "{{.Names}}" | xargs -r docker rm -f
|
||||||
|
|
||||||
|
# GOOD: Only removes containers for current branch
|
||||||
|
test-clean-all:
|
||||||
|
@TEST_INSTANCE_ID=$$(./scripts/get-test-instance-id.sh); \
|
||||||
|
echo "Cleaning up test containers for instance: $$TEST_INSTANCE_ID..."; \
|
||||||
|
docker ps -a --filter "name=test-$$TEST_INSTANCE_ID" --format "{{.Names}}" | xargs -r docker rm -f 2>/dev/null || true; \
|
||||||
|
docker network rm "myproject-test-network-$$TEST_INSTANCE_ID" 2>/dev/null || true
|
||||||
|
```
|
||||||
|
|
||||||
## Docker Compose Patterns
|
## Docker Compose Patterns
|
||||||
|
|
||||||
### Development Environment
|
### Development Environment
|
||||||
@@ -416,6 +469,8 @@ test-infra-down:
|
|||||||
| Verbose test output | Context exhaustion | Use rich progress display, details only on failure |
|
| Verbose test output | Context exhaustion | Use rich progress display, details only on failure |
|
||||||
| Single test stage | Slow feedback, hard to debug | Separate unit → service → integration |
|
| Single test stage | Slow feedback, hard to debug | Separate unit → service → integration |
|
||||||
| No branch isolation | Concurrent branches conflict | Use `TEST_INSTANCE_ID` from git branch |
|
| No branch isolation | Concurrent branches conflict | Use `TEST_INSTANCE_ID` from git branch |
|
||||||
|
| No `COMPOSE_PROJECT_NAME` | Worktrees share images, builds conflict | Set `COMPOSE_PROJECT_NAME=test-${TEST_INSTANCE_ID}` |
|
||||||
|
| Global test cleanup | Kills tests in other worktrees | Scope cleanup to current `TEST_INSTANCE_ID` |
|
||||||
| Building all services on every change | Slow CI | Use matrix strategy, only build changed services |
|
| Building all services on every change | Slow CI | Use matrix strategy, only build changed services |
|
||||||
|
|
||||||
## Quick Reference
|
## Quick Reference
|
||||||
@@ -440,6 +495,9 @@ SERVICE=$1
|
|||||||
TEST_INSTANCE_ID=$(./scripts/get-test-instance-id.sh)
|
TEST_INSTANCE_ID=$(./scripts/get-test-instance-id.sh)
|
||||||
export TEST_INSTANCE_ID
|
export TEST_INSTANCE_ID
|
||||||
|
|
||||||
|
# CRITICAL: Isolate Docker images between worktrees
|
||||||
|
export COMPOSE_PROJECT_NAME="test-${TEST_INSTANCE_ID}"
|
||||||
|
|
||||||
# Start service-specific containers
|
# Start service-specific containers
|
||||||
cd "services/${SERVICE}/deploy/test"
|
cd "services/${SERVICE}/deploy/test"
|
||||||
docker compose up -d --build --wait
|
docker compose up -d --build --wait
|
||||||
|
|||||||
Reference in New Issue
Block a user