mirror of
https://github.com/dograh-hq/dograh.git
synced 2026-06-07 07:55:16 +02:00
chore: update setup docs
This commit is contained in:
parent
15a7cd5b6d
commit
418775cee1
7 changed files with 457 additions and 39 deletions
30
scripts/CLAUDE.md
Normal file
30
scripts/CLAUDE.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# scripts/
|
||||
|
||||
## Bash ↔ PowerShell parity — keep them in sync
|
||||
|
||||
Most contributor-facing scripts ship as a `.sh` + `.ps1` pair so macOS/Linux and Windows users get the same workflow. **When you edit one, edit the other in the same change.** Env-var names, defaults, flags, and behavior should match — if `start_services_dev.sh` reads `HEALTH_MAX_ATTEMPTS`, so should `start_services_dev.ps1`.
|
||||
|
||||
Current pairs:
|
||||
- `setup_fork.{sh,ps1}` — contributor bootstrap (git remotes, submodule, venv, env files)
|
||||
- `setup_requirements.{sh,ps1}` — Python + pipecat dependency install
|
||||
- `start_services_dev.{sh,ps1}` — local backend launcher (auto-reload + health-check wait)
|
||||
- `stop_services.{sh,ps1}`
|
||||
- `makemigrate.{sh,ps1}` / `migrate.{sh,ps1}` — Alembic helpers
|
||||
|
||||
Bash-only (deployment / CI / OSS-user setup — not intended for Windows contributors):
|
||||
- `start_services.sh` — VM production
|
||||
- `start_services_docker.sh` — Docker image CMD
|
||||
- `rolling_update.sh` — zero-downtime VM redeploy
|
||||
- `setup_local.sh` / `setup_remote.sh` — OSS Docker-compose setup
|
||||
- `format.sh` / `lint.sh` / `pre_commit.sh`
|
||||
- `generate_sdk.sh` / `release_sdks.sh` / `dump_docs_openapi.py`
|
||||
|
||||
## The three "start" scripts — pick the right one
|
||||
|
||||
| Script | Where it runs | Key behavior |
|
||||
| ----------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `start_services_dev.sh` | Local dev shell | `uvicorn --reload`, exits after launching, restart by re-running, single arq worker, waits for `/api/v1/health` before exiting. |
|
||||
| `start_services.sh` | VM production | Multi-port uvicorn behind nginx, `sudo nginx -t && systemctl reload`, writes `run/active_band` for `rolling_update.sh`. |
|
||||
| `start_services_docker.sh` | Docker image `CMD` | PID 1: traps SIGTERM, uvicorn `--workers $FASTAPI_WORKERS`, `wait -n` so a dying child tears the container down. |
|
||||
|
||||
If you find yourself adding nginx/sudo logic to the dev script, or `--reload` to the production/Docker scripts, stop — you probably want a different file.
|
||||
165
scripts/setup_fork.ps1
Normal file
165
scripts/setup_fork.ps1
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
#!/usr/bin/env pwsh
|
||||
# Contributor bootstrap (Windows). Run this once after cloning your fork.
|
||||
# Configures git remotes (origin = your fork, upstream = dograh-hq/dograh),
|
||||
# initializes the pipecat submodule, creates the Python venv, and copies
|
||||
# the .env templates.
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$UpstreamUrl = 'https://github.com/dograh-hq/dograh.git'
|
||||
$CanonicalHttps = $UpstreamUrl
|
||||
$CanonicalSsh = 'git@github.com:dograh-hq/dograh.git'
|
||||
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$BaseDir = Split-Path -Parent $ScriptDir
|
||||
Set-Location $BaseDir
|
||||
|
||||
# Must be inside a git repo
|
||||
try {
|
||||
git rev-parse --git-dir | Out-Null
|
||||
} catch {
|
||||
Write-Host 'Error: not a git repository. Run this from inside your cloned fork.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host '+==============================================================+' -ForegroundColor Blue
|
||||
Write-Host '| Dograh Contributor Bootstrap |' -ForegroundColor Blue
|
||||
Write-Host '+==============================================================+' -ForegroundColor Blue
|
||||
Write-Host ''
|
||||
|
||||
function Get-RemoteUrl([string]$Name) {
|
||||
try { return (git remote get-url $Name 2>$null) } catch { return $null }
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
### 1) Configure git remotes
|
||||
###############################################################################
|
||||
|
||||
Write-Host '[1/4] Configuring git remotes' -ForegroundColor Blue
|
||||
|
||||
$currentOrigin = Get-RemoteUrl 'origin'
|
||||
|
||||
$needsForkPrompt = $false
|
||||
if (-not $currentOrigin) {
|
||||
$needsForkPrompt = $true
|
||||
} elseif ($currentOrigin -eq $CanonicalHttps -or $currentOrigin -eq $CanonicalSsh) {
|
||||
Write-Host "origin currently points at the canonical repo ($currentOrigin)." -ForegroundColor Yellow
|
||||
Write-Host 'You should push to your own fork, not the canonical repo.' -ForegroundColor Yellow
|
||||
$needsForkPrompt = $true
|
||||
}
|
||||
|
||||
if ($needsForkPrompt) {
|
||||
Write-Host 'Enter your fork URL (e.g. https://github.com/<YOUR_HANDLE>/dograh.git):' -ForegroundColor Yellow
|
||||
$forkUrl = (Read-Host '>').Trim()
|
||||
if (-not $forkUrl) {
|
||||
Write-Host 'Fork URL is required.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
if ($currentOrigin) {
|
||||
git remote remove origin | Out-Null
|
||||
}
|
||||
git remote add origin $forkUrl
|
||||
Write-Host "OK origin set to $forkUrl" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "OK origin already set: $currentOrigin" -ForegroundColor Green
|
||||
}
|
||||
|
||||
$existingUpstream = Get-RemoteUrl 'upstream'
|
||||
if (-not $existingUpstream) {
|
||||
git remote add upstream $UpstreamUrl
|
||||
Write-Host "OK upstream set to $UpstreamUrl" -ForegroundColor Green
|
||||
} elseif ($existingUpstream -ne $UpstreamUrl -and $existingUpstream -ne $CanonicalSsh) {
|
||||
Write-Host "upstream currently points at $existingUpstream (expected $UpstreamUrl)." -ForegroundColor Yellow
|
||||
$reset = (Read-Host 'Reset upstream to dograh-hq/dograh? [y/N]').Trim()
|
||||
if ($reset -match '^[Yy]') {
|
||||
git remote set-url upstream $UpstreamUrl
|
||||
Write-Host "OK upstream reset to $UpstreamUrl" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host 'Leaving upstream alone.' -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host 'OK upstream already set' -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
git remote -v
|
||||
Write-Host ''
|
||||
|
||||
###############################################################################
|
||||
### 2) Initialize submodules
|
||||
###############################################################################
|
||||
|
||||
Write-Host '[2/4] Initializing pipecat submodule' -ForegroundColor Blue
|
||||
git submodule update --init --recursive
|
||||
Write-Host 'OK submodules initialized' -ForegroundColor Green
|
||||
Write-Host ''
|
||||
|
||||
###############################################################################
|
||||
### 3) Python venv
|
||||
###############################################################################
|
||||
|
||||
Write-Host '[3/4] Python virtual environment' -ForegroundColor Blue
|
||||
$VenvPath = Join-Path $BaseDir 'venv'
|
||||
$VenvActivate = Join-Path $VenvPath 'Scripts/Activate.ps1'
|
||||
|
||||
if (Test-Path $VenvActivate) {
|
||||
Write-Host "OK venv already exists at $VenvPath" -ForegroundColor Green
|
||||
} else {
|
||||
$py = $null
|
||||
foreach ($candidate in @('python3.13', 'python', 'python3')) {
|
||||
if (Get-Command $candidate -ErrorAction SilentlyContinue) {
|
||||
$py = $candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
if (-not $py) {
|
||||
Write-Host 'Error: no python interpreter found on PATH. Install Python 3.13.' -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
& $py -m venv $VenvPath
|
||||
$ver = (& $py --version)
|
||||
Write-Host "OK venv created at $VenvPath using $py ($ver)" -ForegroundColor Green
|
||||
}
|
||||
Write-Host ''
|
||||
|
||||
###############################################################################
|
||||
### 4) .env files
|
||||
###############################################################################
|
||||
|
||||
Write-Host '[4/4] Environment files' -ForegroundColor Blue
|
||||
$pairs = @(
|
||||
@{ Src = 'api/.env.example'; Dst = 'api/.env' },
|
||||
@{ Src = 'ui/.env.example'; Dst = 'ui/.env' }
|
||||
)
|
||||
foreach ($p in $pairs) {
|
||||
if (Test-Path $p.Dst) {
|
||||
Write-Host "OK $($p.Dst) already exists" -ForegroundColor Green
|
||||
} elseif (Test-Path $p.Src) {
|
||||
Copy-Item $p.Src $p.Dst
|
||||
Write-Host "OK created $($p.Dst) from $($p.Src)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Host "WARN $($p.Src) not found, skipping" -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
Write-Host ''
|
||||
|
||||
###############################################################################
|
||||
### Done
|
||||
###############################################################################
|
||||
|
||||
Write-Host '+==============================================================+' -ForegroundColor Green
|
||||
Write-Host '| Bootstrap complete |' -ForegroundColor Green
|
||||
Write-Host '+==============================================================+' -ForegroundColor Green
|
||||
Write-Host ''
|
||||
Write-Host 'Next steps:' -ForegroundColor Yellow
|
||||
Write-Host ' 1. .\venv\Scripts\Activate.ps1'
|
||||
Write-Host ' 2. .\scripts\setup_requirements.ps1'
|
||||
Write-Host ' 3. cd ui; npm install; cd ..'
|
||||
Write-Host ' 4. docker compose -f docker-compose-local.yaml up -d'
|
||||
Write-Host ' 5. .\scripts\start_services_dev.ps1'
|
||||
Write-Host ''
|
||||
Write-Host 'To sync your fork with upstream later:' -ForegroundColor Yellow
|
||||
Write-Host ' git fetch upstream'
|
||||
Write-Host ' git checkout main; git merge upstream/main'
|
||||
Write-Host ' git push origin main'
|
||||
Write-Host ''
|
||||
162
scripts/setup_fork.sh
Executable file
162
scripts/setup_fork.sh
Executable file
|
|
@ -0,0 +1,162 @@
|
|||
#!/usr/bin/env bash
|
||||
# Contributor bootstrap. Run this once after cloning your fork.
|
||||
# Configures git remotes (origin = your fork, upstream = dograh-hq/dograh),
|
||||
# initializes the pipecat submodule, creates the Python venv, and copies
|
||||
# the .env templates.
|
||||
|
||||
set -e
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
UPSTREAM_URL="https://github.com/dograh-hq/dograh.git"
|
||||
|
||||
BASE_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)"
|
||||
cd "$BASE_DIR"
|
||||
|
||||
if ! git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
echo -e "${RED}Error: not a git repository. Run this from inside your cloned fork.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}╔══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BLUE}║ Dograh Contributor Bootstrap ║${NC}"
|
||||
echo -e "${BLUE}╚══════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
|
||||
###############################################################################
|
||||
### 1) Configure git remotes
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[1/4] Configuring git remotes${NC}"
|
||||
|
||||
current_origin=$(git remote get-url origin 2>/dev/null || echo "")
|
||||
canonical_https="https://github.com/dograh-hq/dograh.git"
|
||||
canonical_ssh="git@github.com:dograh-hq/dograh.git"
|
||||
|
||||
# If origin is missing or points at the canonical repo (i.e. user cloned the
|
||||
# canonical repo directly without forking), prompt for the fork URL.
|
||||
needs_fork_prompt=false
|
||||
if [[ -z "$current_origin" ]]; then
|
||||
needs_fork_prompt=true
|
||||
elif [[ "$current_origin" == "$canonical_https" || "$current_origin" == "$canonical_ssh" ]]; then
|
||||
echo -e "${YELLOW}origin currently points at the canonical repo ($current_origin).${NC}"
|
||||
echo -e "${YELLOW}You should push to your own fork, not the canonical repo.${NC}"
|
||||
needs_fork_prompt=true
|
||||
fi
|
||||
|
||||
if $needs_fork_prompt; then
|
||||
echo -e "${YELLOW}Enter your fork URL (e.g. https://github.com/<YOUR_HANDLE>/dograh.git):${NC}"
|
||||
read -r -p "> " FORK_URL
|
||||
if [[ -z "$FORK_URL" ]]; then
|
||||
echo -e "${RED}Fork URL is required.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "$current_origin" ]]; then
|
||||
git remote remove origin
|
||||
fi
|
||||
git remote add origin "$FORK_URL"
|
||||
echo -e "${GREEN}✓ origin set to $FORK_URL${NC}"
|
||||
else
|
||||
echo -e "${GREEN}✓ origin already set: $current_origin${NC}"
|
||||
fi
|
||||
|
||||
existing_upstream=$(git remote get-url upstream 2>/dev/null || echo "")
|
||||
if [[ -z "$existing_upstream" ]]; then
|
||||
git remote add upstream "$UPSTREAM_URL"
|
||||
echo -e "${GREEN}✓ upstream set to $UPSTREAM_URL${NC}"
|
||||
elif [[ "$existing_upstream" != "$UPSTREAM_URL" && "$existing_upstream" != "$canonical_ssh" ]]; then
|
||||
echo -e "${YELLOW}upstream currently points at $existing_upstream (expected $UPSTREAM_URL).${NC}"
|
||||
echo -e "${YELLOW}Reset upstream to dograh-hq/dograh? [y/N]:${NC}"
|
||||
read -r -p "> " RESET_UPSTREAM
|
||||
if [[ "$RESET_UPSTREAM" =~ ^[Yy] ]]; then
|
||||
git remote set-url upstream "$UPSTREAM_URL"
|
||||
echo -e "${GREEN}✓ upstream reset to $UPSTREAM_URL${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}Leaving upstream alone.${NC}"
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}✓ upstream already set${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
git remote -v
|
||||
echo ""
|
||||
|
||||
###############################################################################
|
||||
### 2) Initialize submodules
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[2/4] Initializing pipecat submodule${NC}"
|
||||
git submodule update --init --recursive
|
||||
echo -e "${GREEN}✓ submodules initialized${NC}"
|
||||
echo ""
|
||||
|
||||
###############################################################################
|
||||
### 3) Python venv
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[3/4] Python virtual environment${NC}"
|
||||
VENV_PATH="$BASE_DIR/venv"
|
||||
|
||||
if [[ -d "$VENV_PATH" && -f "$VENV_PATH/bin/activate" ]]; then
|
||||
echo -e "${GREEN}✓ venv already exists at $VENV_PATH${NC}"
|
||||
else
|
||||
PY=""
|
||||
for candidate in python3.13 python3 python; do
|
||||
if command -v "$candidate" >/dev/null 2>&1; then
|
||||
PY="$candidate"
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [[ -z "$PY" ]]; then
|
||||
echo -e "${RED}Error: no python interpreter found on PATH. Install Python 3.13.${NC}"
|
||||
exit 1
|
||||
fi
|
||||
"$PY" -m venv "$VENV_PATH"
|
||||
echo -e "${GREEN}✓ venv created at $VENV_PATH using $PY ($("$PY" --version))${NC}"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
###############################################################################
|
||||
### 4) .env files
|
||||
###############################################################################
|
||||
|
||||
echo -e "${BLUE}[4/4] Environment files${NC}"
|
||||
for pair in "api/.env.example|api/.env" "ui/.env.example|ui/.env"; do
|
||||
src="${pair%|*}"
|
||||
dst="${pair#*|}"
|
||||
if [[ -f "$dst" ]]; then
|
||||
echo -e "${GREEN}✓ $dst already exists${NC}"
|
||||
elif [[ -f "$src" ]]; then
|
||||
cp "$src" "$dst"
|
||||
echo -e "${GREEN}✓ created $dst from $src${NC}"
|
||||
else
|
||||
echo -e "${YELLOW}⚠ $src not found, skipping${NC}"
|
||||
fi
|
||||
done
|
||||
echo ""
|
||||
|
||||
###############################################################################
|
||||
### Done
|
||||
###############################################################################
|
||||
|
||||
echo -e "${GREEN}╔══════════════════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${GREEN}║ Bootstrap complete ║${NC}"
|
||||
echo -e "${GREEN}╚══════════════════════════════════════════════════════════════╝${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Next steps:${NC}"
|
||||
echo " 1. source venv/bin/activate"
|
||||
echo " 2. bash scripts/setup_requirements.sh"
|
||||
echo " 3. (cd ui && npm install)"
|
||||
echo " 4. docker compose -f docker-compose-local.yaml up -d"
|
||||
echo " 5. bash scripts/start_services_dev.sh"
|
||||
echo ""
|
||||
echo -e "${YELLOW}To sync your fork with upstream later:${NC}"
|
||||
echo " git fetch upstream"
|
||||
echo " git checkout main && git merge upstream/main"
|
||||
echo " git push origin main"
|
||||
echo ""
|
||||
|
|
@ -46,7 +46,11 @@ if (Test-Path $EnvFile) {
|
|||
}
|
||||
}
|
||||
|
||||
if (-not $env:UVICORN_BASE_PORT) { $env:UVICORN_BASE_PORT = '8000' }
|
||||
if (-not $env:UVICORN_BASE_PORT) { $env:UVICORN_BASE_PORT = '8000' }
|
||||
|
||||
$HealthEndpoint = '/api/v1/health'
|
||||
$HealthMaxAttempts = if ($env:HEALTH_MAX_ATTEMPTS) { [int]$env:HEALTH_MAX_ATTEMPTS } else { 30 }
|
||||
$HealthInterval = if ($env:HEALTH_INTERVAL) { [int]$env:HEALTH_INTERVAL } else { 2 }
|
||||
|
||||
###############################################################################
|
||||
### 2) Define services
|
||||
|
|
@ -129,7 +133,35 @@ foreach ($spec in $serviceSpecs) {
|
|||
}
|
||||
|
||||
###############################################################################
|
||||
### 8) Summary
|
||||
### 8) Wait for uvicorn health check
|
||||
###############################################################################
|
||||
|
||||
$healthUrl = "http://127.0.0.1:$($env:UVICORN_BASE_PORT)$HealthEndpoint"
|
||||
Write-Host "Waiting for uvicorn health check at $healthUrl ..."
|
||||
|
||||
$healthy = $false
|
||||
for ($attempt = 1; $attempt -le $HealthMaxAttempts; $attempt++) {
|
||||
try {
|
||||
$resp = Invoke-WebRequest -Uri $healthUrl -UseBasicParsing -TimeoutSec 2 -ErrorAction Stop
|
||||
if ($resp.StatusCode -eq 200) {
|
||||
Write-Host "OK uvicorn healthy (attempt $attempt)"
|
||||
$healthy = $true
|
||||
break
|
||||
}
|
||||
} catch {
|
||||
# connection refused / timeout / non-200 — keep polling
|
||||
}
|
||||
Start-Sleep -Seconds $HealthInterval
|
||||
}
|
||||
|
||||
if (-not $healthy) {
|
||||
Write-Host "FAIL uvicorn FAILED health check after $HealthMaxAttempts attempts."
|
||||
Write-Host " Check logs: Get-Content logs/latest/uvicorn.log -Wait"
|
||||
exit 1
|
||||
}
|
||||
|
||||
###############################################################################
|
||||
### 9) Summary
|
||||
###############################################################################
|
||||
|
||||
Write-Host ""
|
||||
|
|
|
|||
|
|
@ -19,6 +19,10 @@ VENV_PATH="$BASE_DIR/venv"
|
|||
|
||||
LOG_TO_FILE=${LOG_TO_FILE:-true}
|
||||
|
||||
HEALTH_CHECK_ENDPOINT="/api/v1/health"
|
||||
HEALTH_MAX_ATTEMPTS=${HEALTH_MAX_ATTEMPTS:-30}
|
||||
HEALTH_INTERVAL=${HEALTH_INTERVAL:-2}
|
||||
|
||||
cd "$BASE_DIR"
|
||||
echo "Starting Dograh Services (DEV MODE) at $(date) in BASE_DIR: ${BASE_DIR}"
|
||||
echo "Auto-reload enabled for api/ directory changes"
|
||||
|
|
@ -193,7 +197,32 @@ for i in "${!SERVICE_NAMES[@]}"; do
|
|||
done
|
||||
|
||||
###############################################################################
|
||||
### 8) Summary
|
||||
### 8) Wait for uvicorn health check
|
||||
###############################################################################
|
||||
|
||||
echo "Waiting for uvicorn health check at http://127.0.0.1:${UVICORN_BASE_PORT}${HEALTH_CHECK_ENDPOINT} ..."
|
||||
|
||||
healthy=false
|
||||
for ((attempt = 1; attempt <= HEALTH_MAX_ATTEMPTS; attempt++)); do
|
||||
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
"http://127.0.0.1:${UVICORN_BASE_PORT}${HEALTH_CHECK_ENDPOINT}" 2>/dev/null || echo "000")
|
||||
|
||||
if [[ "$http_code" == "200" ]]; then
|
||||
echo "✓ uvicorn healthy (attempt $attempt)"
|
||||
healthy=true
|
||||
break
|
||||
fi
|
||||
sleep "$HEALTH_INTERVAL"
|
||||
done
|
||||
|
||||
if ! $healthy; then
|
||||
echo "✗ uvicorn FAILED health check after $HEALTH_MAX_ATTEMPTS attempts."
|
||||
echo " Check logs: tail -f $LOG_DIR/uvicorn.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
###############################################################################
|
||||
### 9) Summary
|
||||
###############################################################################
|
||||
|
||||
echo
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue