|
| 1 | +# PR Preview Environments |
| 2 | + |
| 3 | +Automated isolated staging environments for every pull request. |
| 4 | + |
| 5 | +--- |
| 6 | + |
| 7 | +## 🚀 Quick Start |
| 8 | + |
| 9 | +1. **Create PR** to `main` branch |
| 10 | +2. **Wait 5-10 min** for deployment |
| 11 | +3. **Connect to Tailscale** VPN |
| 12 | +4. **Click backend URL** in PR comment |
| 13 | +5. **Test your changes** |
| 14 | + |
| 15 | +Cleanup happens automatically when PR closes/merges. |
| 16 | + |
| 17 | +--- |
| 18 | + |
| 19 | +## 💡 What & Why |
| 20 | + |
| 21 | +### The Problem |
| 22 | +- Manual deployment for testing |
| 23 | +- Environment conflicts between developers |
| 24 | +- Changes merged without full-stack testing |
| 25 | +- Slow feedback loops |
| 26 | + |
| 27 | +### The Solution |
| 28 | +**Automatic isolated environments** that deploy on every PR: |
| 29 | +- ✅ Own database, network, and ports |
| 30 | +- ✅ Run 10+ PRs simultaneously |
| 31 | +- ✅ Auto-cleanup on close/merge |
| 32 | +- ✅ Live in 5-10 minutes |
| 33 | +- ✅ Warm build cache for fast deployments |
| 34 | + |
| 35 | +--- |
| 36 | + |
| 37 | +## 🏗️ How It Works |
| 38 | + |
| 39 | +``` |
| 40 | +PR opened/updated |
| 41 | + → GitHub Actions builds image (uses warm cache) |
| 42 | + → Deploys to RPi5 via Tailscale |
| 43 | + → Bot comments with URLs |
| 44 | + → Test via Tailscale |
| 45 | + → PR closes → Auto cleanup |
| 46 | +
|
| 47 | +Nightly (3 AM UTC) |
| 48 | + → Cache warming builds ARM64 from main |
| 49 | + → PR builds start with warm cache |
| 50 | +``` |
| 51 | + |
| 52 | +**Each PR gets:** |
| 53 | +- Postgres container (fresh DB with migrations) |
| 54 | +- Backend API container (your PR code) |
| 55 | +- Isolated Docker network |
| 56 | +- Unique ports (no conflicts) |
| 57 | + |
| 58 | +--- |
| 59 | + |
| 60 | +## 🔌 Accessing Your Environment |
| 61 | + |
| 62 | +### Prerequisites |
| 63 | +- Tailscale installed and connected |
| 64 | +- Member of team Tailscale network |
| 65 | + |
| 66 | +### Access Steps |
| 67 | + |
| 68 | +**1. Find your preview URL in PR comment:** |
| 69 | +```markdown |
| 70 | +🚀 PR Preview Environment Deployed! |
| 71 | +Backend API: http://neo.rove-barbel.ts.net:4123 |
| 72 | +Health Check: http://neo.rove-barbel.ts.net:4123/health |
| 73 | +``` |
| 74 | + |
| 75 | +**2. Connect to Tailscale:** |
| 76 | +```bash |
| 77 | +tailscale status # Verify connected |
| 78 | +``` |
| 79 | + |
| 80 | +**3. Click URLs** (only works on Tailscale!) |
| 81 | + |
| 82 | +--- |
| 83 | + |
| 84 | +## 🧮 Port Allocation |
| 85 | + |
| 86 | +**Formula:** |
| 87 | +``` |
| 88 | +Backend Port = 4000 + PR_NUMBER |
| 89 | +Postgres Port = 5432 + PR_NUMBER |
| 90 | +``` |
| 91 | + |
| 92 | +**Examples:** |
| 93 | +- PR #1 → Backend: `4001`, Postgres: `5433` |
| 94 | +- PR #123 → Backend: `4123`, Postgres: `5555` |
| 95 | +- PR #999 → Backend: `4999`, Postgres: `6431` |
| 96 | + |
| 97 | +--- |
| 98 | + |
| 99 | +## 🧪 Testing Your Changes |
| 100 | + |
| 101 | +### Health Check |
| 102 | +```bash |
| 103 | +curl http://neo.rove-barbel.ts.net:4123/health |
| 104 | +``` |
| 105 | + |
| 106 | +### API Testing |
| 107 | +```bash |
| 108 | +PR_NUM=123 |
| 109 | +BASE_URL="http://neo.rove-barbel.ts.net:$((4000 + PR_NUM))" |
| 110 | + |
| 111 | +curl $BASE_URL/api/v1/users |
| 112 | +curl $BASE_URL/health |
| 113 | +``` |
| 114 | + |
| 115 | +### Database Access |
| 116 | +```bash |
| 117 | +psql -h neo.rove-barbel.ts.net -p 5555 -U refactor -d refactor |
| 118 | +``` |
| 119 | + |
| 120 | +### Browser |
| 121 | +Open while connected to Tailscale: |
| 122 | +``` |
| 123 | +http://neo.rove-barbel.ts.net:4123/health |
| 124 | +``` |
| 125 | + |
| 126 | +--- |
| 127 | + |
| 128 | +## 🔧 Troubleshooting |
| 129 | + |
| 130 | +### ❌ Can't Access URL |
| 131 | + |
| 132 | +**Check Tailscale:** |
| 133 | +```bash |
| 134 | +tailscale status | grep neo |
| 135 | +``` |
| 136 | + |
| 137 | +**Verify container running:** |
| 138 | +```bash |
| 139 | +ssh [email protected] 'docker ps | grep pr-123' |
| 140 | +``` |
| 141 | + |
| 142 | +**Check deployment succeeded:** |
| 143 | +- Go to PR → Checks tab → Look for green checkmark |
| 144 | + |
| 145 | +### ❌ Deployment Failed |
| 146 | + |
| 147 | +**View logs:** PR → Checks tab → Click failed step |
| 148 | + |
| 149 | +**Common issues:** |
| 150 | +- Build errors → Check Rust compilation logs |
| 151 | +- SSH timeout → Verify Tailscale OAuth in GitHub secrets |
| 152 | +- Container won't start → Check backend logs on RPi5 |
| 153 | + |
| 154 | +### ❌ Slow Deployment (10+ min) |
| 155 | + |
| 156 | +**Normal times:** |
| 157 | +- **First PR after midnight:** 5-10 min (cache warmed nightly) |
| 158 | +- **Subsequent PRs:** 3-5 min (using cache) |
| 159 | +- **Cache miss:** 15-20 min (full rebuild) |
| 160 | + |
| 161 | +**If unexpectedly slow:** |
| 162 | +- Cache corruption → Check nightly cache warming workflow |
| 163 | +- Build complexity → Large code changes take longer |
| 164 | +- RPi5 load → Multiple simultaneous builds |
| 165 | + |
| 166 | +**Verify cache warming:** |
| 167 | +```bash |
| 168 | +# Check nightly workflow ran successfully |
| 169 | +GitHub → Actions → "Warm Build Cache" → Latest run |
| 170 | +``` |
| 171 | + |
| 172 | +### 🔍 View Container Logs |
| 173 | + |
| 174 | +```bash |
| 175 | + |
| 176 | + |
| 177 | +# Backend logs |
| 178 | +docker logs pr-123-backend-1 --tail 50 |
| 179 | + |
| 180 | +# Migration logs |
| 181 | +docker logs pr-123-migrator-1 |
| 182 | + |
| 183 | +# All PR containers |
| 184 | +docker ps --filter "name=pr-" |
| 185 | +``` |
| 186 | + |
| 187 | +--- |
| 188 | + |
| 189 | +## ⚙️ Configuration |
| 190 | + |
| 191 | +### Update Environment Variables |
| 192 | + |
| 193 | +**Location:** `Settings → Environments → pr-preview` |
| 194 | + |
| 195 | +**Common changes:** |
| 196 | +- `BACKEND_LOG_LEVEL`: `DEBUG` → `INFO` |
| 197 | +- `BACKEND_SESSION_EXPIRY`: `86400` (24h) → `3600` (1h) |
| 198 | + |
| 199 | +### Add New Environment Variable |
| 200 | + |
| 201 | +**1. Add to GitHub:** `Settings → Environments → pr-preview → Add secret` |
| 202 | + |
| 203 | +**2. Add to workflow:** |
| 204 | +```yaml |
| 205 | +env: |
| 206 | + MY_VAR: ${{ secrets.MY_VAR }} |
| 207 | +``` |
| 208 | +
|
| 209 | +**3. Add to SSH export in deployment step:** |
| 210 | +```bash |
| 211 | +export MY_VAR='${MY_VAR}' |
| 212 | +``` |
| 213 | + |
| 214 | +**4. Add to `docker-compose.pr-preview.yaml`:** |
| 215 | +```yaml |
| 216 | +environment: |
| 217 | + MY_VAR: ${MY_VAR} |
| 218 | +``` |
| 219 | +
|
| 220 | +--- |
| 221 | +
|
| 222 | +## 🧹 Cleanup Behavior |
| 223 | +
|
| 224 | +**Automatic cleanup when PR closes:** |
| 225 | +- ✅ Containers stopped and removed |
| 226 | +- ✅ Docker images deleted |
| 227 | +- ✅ Networks removed |
| 228 | +- ✅ Compose files deleted |
| 229 | +
|
| 230 | +**Volume retention:** |
| 231 | +- **Merged PRs:** 7-day retention (allows post-merge debugging) |
| 232 | +- **Closed PRs:** Immediate removal (frees space) |
| 233 | +
|
| 234 | +**Manual cleanup (if needed):** |
| 235 | +```bash |
| 236 | + |
| 237 | +docker compose -p pr-123 -f pr-123-compose.yaml down |
| 238 | +docker volume rm pr-123_postgres_data |
| 239 | +``` |
| 240 | + |
| 241 | +--- |
| 242 | + |
| 243 | +## 🎯 Manual Deployment (No PR) |
| 244 | + |
| 245 | +**Use workflow dispatch:** |
| 246 | +1. Actions tab → "Deploy PR Preview to RPi5" |
| 247 | +2. Click "Run workflow" |
| 248 | +3. Select branch and options |
| 249 | +4. Click "Run workflow" |
| 250 | + |
| 251 | +**Note:** No PR comment (no PR to comment on) |
| 252 | + |
| 253 | +--- |
| 254 | + |
| 255 | +## 🔥 Build Cache Optimization |
| 256 | + |
| 257 | +### Nightly Cache Warming |
| 258 | +**Automatic process runs at 3 AM UTC:** |
| 259 | +- Builds ARM64 image from latest `main` |
| 260 | +- Populates GitHub Actions cache |
| 261 | +- PR builds start with warm dependencies cache |
| 262 | +- Reduces first-time build from 20min → 5-10min |
| 263 | + |
| 264 | +### Cache Strategy |
| 265 | +``` |
| 266 | +Cache Layers: |
| 267 | +1. Rust dependencies (cargo chef) |
| 268 | +2. System packages (apt) |
| 269 | +3. Build artifacts |
| 270 | +4. ARM64 cross-compilation tools |
| 271 | +``` |
| 272 | + |
| 273 | +### Cache Status |
| 274 | +**Check cache health:** |
| 275 | +```bash |
| 276 | +# View cache warming workflow |
| 277 | +GitHub → Actions → "Warm Build Cache" |
| 278 | + |
| 279 | +# Check cache size/usage |
| 280 | +GitHub → Settings → Actions → Caches |
| 281 | +``` |
| 282 | + |
| 283 | +**Force cache refresh:** |
| 284 | +- Enable "Force rebuild" in workflow dispatch |
| 285 | +- Or wait for next nightly warming |
| 286 | + |
| 287 | +--- |
| 288 | + |
| 289 | +## ❓ FAQ |
| 290 | + |
| 291 | +**Q: How many PRs can run simultaneously?** |
| 292 | +A: ~10-15 comfortably on RPi5 |
| 293 | + |
| 294 | +**Q: What if deployment fails?** |
| 295 | +A: PR still mergeable, check workflow logs for errors |
| 296 | + |
| 297 | +**Q: Can I test frontend changes?** |
| 298 | +A: Not yet, backend only (frontend coming later) |
| 299 | + |
| 300 | +**Q: How do I see active environments?** |
| 301 | +```bash |
| 302 | +ssh [email protected] 'docker ps --filter "name=pr-"' |
| 303 | +``` |
| 304 | + |
| 305 | +**Q: Why is my first PR build slow?** |
| 306 | +A: Cache warming runs nightly at 3 AM UTC. PRs before first cache warm take 15-20min. |
| 307 | + |
| 308 | +**Q: Where are the workflows?** |
| 309 | +A: `.github/workflows/deploy-pr-preview.yml` (deploy) |
| 310 | +A: `.github/workflows/cleanup-pr-preview.yml` (cleanup) |
| 311 | +A: `.github/workflows/warm-build-cache.yml` (nightly cache) |
| 312 | + |
| 313 | +--- |
| 314 | + |
| 315 | +## 📁 Key Files |
| 316 | + |
| 317 | +| File | Purpose | |
| 318 | +|------|---------| |
| 319 | +| `.github/workflows/deploy-pr-preview.yml` | Deployment automation | |
| 320 | +| `.github/workflows/cleanup-pr-preview.yml` | Cleanup automation | |
| 321 | +| `.github/workflows/warm-build-cache.yml` | Nightly cache warming | |
| 322 | +| `docker-compose.pr-preview.yaml` | Multi-tenant template | |
| 323 | + |
| 324 | +--- |
| 325 | + |
| 326 | +## 🆘 Getting Help |
| 327 | + |
| 328 | +1. Check troubleshooting section above |
| 329 | +2. Review GitHub Actions logs |
| 330 | +3. SSH to RPi5 and check container logs |
| 331 | +4. Ask in `Levi` Slack |
| 332 | + |
| 333 | +--- |
| 334 | + |
| 335 | +**Last Updated:** 2025-10-23 |
| 336 | +**Maintained By:** Platform Engineering Team (aka Levi) |
0 commit comments