Okay Wish I could say I know exactly. Will do better next time promise lol

This commit is contained in:
2026-02-26 17:47:04 -07:00
parent 2fa50b001c
commit 9e51aac570
727 changed files with 217309 additions and 5801 deletions

View File

@@ -0,0 +1,81 @@
"""
Tiny HTTP server that triggers `mkdocs build --clean` on POST /build.
Runs inside the MkDocs container alongside `mkdocs serve`.
Listens on port 8001 (internal only, not exposed to host).
"""
import subprocess
import json
import time
from http.server import HTTPServer, BaseHTTPRequestHandler
class BuildHandler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != '/build':
self.send_response(404)
self.end_headers()
self.wfile.write(b'{"error":"not found"}')
return
start = time.time()
try:
result = subprocess.run(
['mkdocs', 'build', '--clean'],
cwd='/docs',
capture_output=True,
text=True,
timeout=120,
)
duration = int((time.time() - start) * 1000)
body = json.dumps({
'success': result.returncode == 0,
'output': (result.stdout + result.stderr) or '(no output)',
'duration': duration,
})
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(body.encode())
except subprocess.TimeoutExpired:
duration = int((time.time() - start) * 1000)
body = json.dumps({
'success': False,
'output': 'Build timed out after 120s',
'duration': duration,
})
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(body.encode())
except Exception as e:
duration = int((time.time() - start) * 1000)
body = json.dumps({
'success': False,
'output': f'Build error: {str(e)}',
'duration': duration,
})
self.send_response(500)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(body.encode())
def do_GET(self):
if self.path == '/health':
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(b'{"status":"ok"}')
return
self.send_response(404)
self.end_headers()
def log_message(self, format, *args):
# Suppress default logging to keep container logs clean
pass
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 8001), BuildHandler)
print('Build trigger server listening on :8001')
server.serve_forever()

13
scripts/mkdocs-entrypoint.sh Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/sh
# Entrypoint for MkDocs container: runs both the dev server and the build trigger.
# Start the build trigger server in the background
python /scripts/mkdocs-build-trigger.py &
BUILD_PID=$!
# Start MkDocs serve — restart it on crash so the build trigger stays alive
while true; do
mkdocs serve --dev-addr=0.0.0.0:8000 --watch-theme --livereload || true
echo "MkDocs serve exited, restarting in 5s..."
sleep 5
done

View File

@@ -31,6 +31,7 @@ INFRA_CONTAINERS="v2-postgres redis"
USER_PATHS=(
"mkdocs/docs/"
"mkdocs/mkdocs.yml"
"mkdocs/site/"
"configs/"
"nginx/conf.d/services.conf"
)
@@ -143,7 +144,7 @@ on_failure() {
local exit_code=$?
release_lock
if [[ $exit_code -ne 0 ]] && [[ "$DRY_RUN" != "true" ]]; then
error "Upgrade failed at line $BASH_LINENO (exit code $exit_code)"
error "Upgrade failed at line ${BASH_LINENO[0]} (exit code $exit_code)"
print_rollback_help
info "Log file: $LOG_FILE"
fi
@@ -266,7 +267,7 @@ if [[ "$ROLLBACK" == "true" ]]; then
exit 0
fi
git checkout "$ROLLBACK_COMMIT"
git checkout -B "$BRANCH" "$ROLLBACK_COMMIT"
docker compose build $SOURCE_CONTAINERS
docker compose up -d
success "Rolled back to $ROLLBACK_COMMIT"
@@ -458,18 +459,13 @@ if [[ "$DRY_RUN" == "true" ]]; then
exit 0
fi
# Step 1: Reset generated files (regenerated on container start)
info "Resetting generated files..."
git checkout -- mkdocs/site/ 2>/dev/null || true
success "Reset mkdocs/site/ (regenerated on start)"
# Step 2: Stash user changes if any exist
# Step 1: Stash user changes if any exist
HAS_CHANGES=false
if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then
HAS_CHANGES=true
STASH_NAME="upgrade-${TIMESTAMP}"
info "Stashing local changes as '$STASH_NAME'..."
git stash push -m "$STASH_NAME" --include-untracked
git stash push -m "$STASH_NAME"
success "Local changes stashed"
fi
@@ -499,12 +495,12 @@ if [[ "$HAS_CHANGES" == "true" ]]; then
for user_path in "${USER_PATHS[@]}"; do
CONFLICTED="$(git diff --name-only --diff-filter=U -- "$user_path" 2>/dev/null || true)"
if [[ -n "$CONFLICTED" ]]; then
echo "$CONFLICTED" | while read -r cf; do
while IFS= read -r cf; do
info " Auto-resolving (keeping yours): $cf"
git checkout --theirs "$cf" 2>/dev/null || true
git add "$cf"
done
RESOLVED_COUNT=$((RESOLVED_COUNT + 1))
RESOLVED_COUNT=$((RESOLVED_COUNT + 1))
done < <(echo "$CONFLICTED")
fi
done
@@ -536,7 +532,9 @@ if [[ -f "$PROJECT_DIR/.env.example" ]] && [[ -f "$PROJECT_DIR/.env" ]]; then
key="$(echo "$key" | xargs)"
[[ ! "$key" =~ ^[a-zA-Z_][a-zA-Z0-9_]*$ ]] && continue
if ! grep -q "^${key}=" "$PROJECT_DIR/.env" 2>/dev/null; then
# Append with default value from .env.example
# Strip inline comments and trim whitespace before appending
value="${value%%#*}"
value="$(echo "$value" | xargs)"
echo "${key}=${value}" >> "$PROJECT_DIR/.env"
NEW_VARS+=("$key")
fi
@@ -645,6 +643,12 @@ while true; do
if docker compose exec -T api wget -q --spider http://localhost:4000/api/health 2>/dev/null; then
break
fi
# Detect container crash early (don't wait full timeout)
if ! docker compose ps api --format '{{.State}}' 2>/dev/null | grep -q "running"; then
error "API container exited unexpectedly"
docker compose logs api --tail 20
exit 1
fi
sleep $HEALTH_INTERVAL
API_WAIT=$((API_WAIT + HEALTH_INTERVAL))
if [[ $API_WAIT -ge $HEALTH_TIMEOUT ]]; then
@@ -655,11 +659,21 @@ while true; do
done
success "API healthy (${API_WAIT}s)"
# Start everything else
# Start everything else (exclude one-shot init containers)
info "Starting remaining services..."
docker compose up -d
docker compose up -d \
--scale listmonk-init=0 \
--scale gancio-init=0 \
--scale vaultwarden-init=0
success "All services started"
# Restart Pangolin tunnel connector if running (may hold stale state after nginx rebuild)
if docker ps --format '{{.Names}}' | grep -q 'newt'; then
info "Restarting Pangolin tunnel connector..."
docker compose restart newt 2>/dev/null || true
success "Newt tunnel restarted"
fi
# Restart monitoring if it was running before
if [[ "$MONITORING_WAS_RUNNING" == "true" ]]; then
info "Restarting monitoring stack..."