206 lines
5.9 KiB
PowerShell
206 lines
5.9 KiB
PowerShell
|
|
<#
|
|||
|
|
AZA – Step 12 Fix: Start LOCAL backend with tokens from deploy\.env (no manual edits)
|
|||
|
|
|
|||
|
|
What it does:
|
|||
|
|
- Loads deploy\.env
|
|||
|
|
- Sets process env: MEDWORK_API_TOKENS / MEDWORK_API_TOKEN (as present in .env)
|
|||
|
|
- Attempts to start uvicorn with common app module paths:
|
|||
|
|
1) app:app
|
|||
|
|
2) backend.main:app
|
|||
|
|
3) main:app
|
|||
|
|
- Binds to 127.0.0.1:8000
|
|||
|
|
|
|||
|
|
Run from project root:
|
|||
|
|
powershell -ExecutionPolicy Bypass -File .\deploy\run_backend_local_with_env.ps1
|
|||
|
|
|
|||
|
|
Then re-run authorized test:
|
|||
|
|
cd .\deploy
|
|||
|
|
powershell -ExecutionPolicy Bypass -File .\authorized_test.ps1
|
|||
|
|
#>
|
|||
|
|
|
|||
|
|
[CmdletBinding()]
|
|||
|
|
param(
|
|||
|
|
[string]$EnvFile = ".\deploy\.env",
|
|||
|
|
[string]$BindHost = "127.0.0.1",
|
|||
|
|
[int]$Port = 8000
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
function Load-DotEnv([string]$Path) {
|
|||
|
|
if (-not (Test-Path -LiteralPath $Path)) {
|
|||
|
|
throw "Missing .env file at: $Path"
|
|||
|
|
}
|
|||
|
|
$map = @{}
|
|||
|
|
Get-Content -LiteralPath $Path | ForEach-Object {
|
|||
|
|
$line = $_.Trim()
|
|||
|
|
if ($line.Length -eq 0) { return }
|
|||
|
|
if ($line.StartsWith("#")) { return }
|
|||
|
|
$idx = $line.IndexOf("=")
|
|||
|
|
if ($idx -lt 1) { return }
|
|||
|
|
$k = $line.Substring(0, $idx).Trim()
|
|||
|
|
$v = $line.Substring($idx + 1).Trim()
|
|||
|
|
if (($v.StartsWith('"') -and $v.EndsWith('"')) -or ($v.StartsWith("'") -and $v.EndsWith("'"))) {
|
|||
|
|
$v = $v.Substring(1, $v.Length - 2)
|
|||
|
|
}
|
|||
|
|
$map[$k] = $v
|
|||
|
|
}
|
|||
|
|
return $map
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Write-Host "[AZA] Start local backend with env from $EnvFile"
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
$envMap = Load-DotEnv $EnvFile
|
|||
|
|
} catch {
|
|||
|
|
Write-Host "❌ $($_.Exception.Message)"
|
|||
|
|
exit 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if ($envMap.ContainsKey("MEDWORK_API_TOKENS")) {
|
|||
|
|
$env:MEDWORK_API_TOKENS = $envMap["MEDWORK_API_TOKENS"]
|
|||
|
|
Write-Host " MEDWORK_API_TOKENS: set"
|
|||
|
|
} elseif ($envMap.ContainsKey("MEDWORK_API_TOKEN")) {
|
|||
|
|
$env:MEDWORK_API_TOKEN = $envMap["MEDWORK_API_TOKEN"]
|
|||
|
|
Write-Host " MEDWORK_API_TOKEN: set"
|
|||
|
|
} else {
|
|||
|
|
Write-Host "❌ No MEDWORK_API_TOKENS or MEDWORK_API_TOKEN found in $EnvFile"
|
|||
|
|
exit 1
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# AZA secret key requirement:
|
|||
|
|
# Prefer AZA_SECRET_KEY from .env; otherwise enable dev-mode auto-generated key.
|
|||
|
|
if ($envMap.ContainsKey("AZA_SECRET_KEY") -and $envMap["AZA_SECRET_KEY"].Trim().Length -ge 32) {
|
|||
|
|
$env:AZA_SECRET_KEY = $envMap["AZA_SECRET_KEY"]
|
|||
|
|
Write-Host " AZA_SECRET_KEY: set (from .env)"
|
|||
|
|
} else {
|
|||
|
|
$env:AZA_ENV = "dev"
|
|||
|
|
Write-Host " AZA_ENV: dev (AZA_SECRET_KEY not present/too short in .env)"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Optional: keep build leak-free if your backend uses AZA_BUILD
|
|||
|
|
if ($envMap.ContainsKey("AZA_BUILD")) {
|
|||
|
|
$env:AZA_BUILD = $envMap["AZA_BUILD"]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Write-Host " Binding: http://$BindHost`:$Port"
|
|||
|
|
Write-Host ""
|
|||
|
|
|
|||
|
|
$preferredTarget = "workforce_planner.api.app:app"
|
|||
|
|
$candidates = @($preferredTarget, "app:app", "backend.main:app", "main:app")
|
|||
|
|
|
|||
|
|
function Try-Start([string]$target) {
|
|||
|
|
Write-Host "Trying: uvicorn $target --host $BindHost --port $Port"
|
|||
|
|
# Use python -m uvicorn to avoid PATH issues
|
|||
|
|
& python -m uvicorn $target --host $BindHost --port $Port
|
|||
|
|
if ($LASTEXITCODE -eq 0) { return $true }
|
|||
|
|
return $false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Write-Host "NOTE: This will run the server in the foreground. Leave this window open while testing."
|
|||
|
|
Write-Host ""
|
|||
|
|
|
|||
|
|
function Try-StartFile([string]$filePath) {
|
|||
|
|
Write-Host "Trying: python $filePath"
|
|||
|
|
& python $filePath
|
|||
|
|
if ($LASTEXITCODE -eq 0) { return $true }
|
|||
|
|
return $false
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function To-ModulePath([string]$filePath) {
|
|||
|
|
$p = $filePath.Replace("\", "/")
|
|||
|
|
if ($p.StartsWith("./")) { $p = $p.Substring(2) }
|
|||
|
|
if ($p.EndsWith(".py")) { $p = $p.Substring(0, $p.Length - 3) }
|
|||
|
|
return ($p -replace "/", ".")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function Repo-FastApiCandidates {
|
|||
|
|
$paths = @(
|
|||
|
|
"main.py",
|
|||
|
|
"backend\main.py",
|
|||
|
|
"backend\app.py",
|
|||
|
|
"server.py",
|
|||
|
|
"api.py",
|
|||
|
|
"asgi.py",
|
|||
|
|
"app.py",
|
|||
|
|
"app\main.py",
|
|||
|
|
"src\main.py",
|
|||
|
|
"src\backend\main.py",
|
|||
|
|
"aza_backend\main.py",
|
|||
|
|
"aza\main.py"
|
|||
|
|
)
|
|||
|
|
$found = @()
|
|||
|
|
foreach ($p in $paths) {
|
|||
|
|
if (Test-Path -LiteralPath $p) { $found += $p }
|
|||
|
|
}
|
|||
|
|
# If nothing found, do a shallow-ish search (PS5.1 compatible) for common entry filenames
|
|||
|
|
if ($found.Count -eq 0) {
|
|||
|
|
$filters = @("main.py","app.py","server.py","api.py","asgi.py")
|
|||
|
|
try {
|
|||
|
|
$root = (Resolve-Path .).Path
|
|||
|
|
$all = Get-ChildItem -Path . -Recurse -File -ErrorAction SilentlyContinue |
|
|||
|
|
Where-Object { $filters -contains $_.Name }
|
|||
|
|
|
|||
|
|
foreach ($fi in $all) {
|
|||
|
|
# approximate depth by counting separators in relative path
|
|||
|
|
$rel = Resolve-Path $fi.FullName -Relative
|
|||
|
|
$sepCount = ($rel.ToString().Split(@("\","/")) | Where-Object { $_ -ne "." -and $_ -ne "" }).Count - 1
|
|||
|
|
if ($sepCount -le 3) {
|
|||
|
|
$found += $rel
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
} catch { }
|
|||
|
|
}
|
|||
|
|
# de-dup
|
|||
|
|
return ($found | Select-Object -Unique)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 1) Try preferred known target first (your repo)
|
|||
|
|
Write-Host "Preferred target: $preferredTarget"
|
|||
|
|
Write-Host ""
|
|||
|
|
|
|||
|
|
foreach ($t in $candidates) {
|
|||
|
|
$ok = Try-Start $t
|
|||
|
|
if ($ok) { exit 0 }
|
|||
|
|
Write-Host " (failed) $t"
|
|||
|
|
Write-Host ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 2) Try repo-discovered file candidates
|
|||
|
|
$files = Repo-FastApiCandidates
|
|||
|
|
Write-Host "Discovered candidate backend files: $($files.Count)"
|
|||
|
|
if ($files.Count -gt 0) {
|
|||
|
|
$files | ForEach-Object { Write-Host " - $_" }
|
|||
|
|
} else {
|
|||
|
|
Write-Host " (none found within ~3 levels for: main.py/app.py/server.py/api.py/asgi.py)"
|
|||
|
|
}
|
|||
|
|
Write-Host ""
|
|||
|
|
|
|||
|
|
if ($files.Count -gt 0) {
|
|||
|
|
foreach ($f in $files) {
|
|||
|
|
# First: try running the file directly (in case it self-starts uvicorn)
|
|||
|
|
$okFile = Try-StartFile $f
|
|||
|
|
if ($okFile) { exit 0 }
|
|||
|
|
Write-Host " (failed) python $f"
|
|||
|
|
Write-Host ""
|
|||
|
|
|
|||
|
|
# Second: try uvicorn with module:app
|
|||
|
|
$mod = To-ModulePath $f
|
|||
|
|
$target = "$mod`:app"
|
|||
|
|
$ok = Try-Start $target
|
|||
|
|
if ($ok) { exit 0 }
|
|||
|
|
Write-Host " (failed) $target"
|
|||
|
|
Write-Host ""
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Write-Host "FAIL Could not start uvicorn with known module targets."
|
|||
|
|
Write-Host "Checked module candidates:"
|
|||
|
|
$candidates | ForEach-Object { Write-Host " - $_" }
|
|||
|
|
if ($files -and $files.Count -gt 0) {
|
|||
|
|
Write-Host "Checked discovered files:"
|
|||
|
|
$files | ForEach-Object { Write-Host " - $_" }
|
|||
|
|
}
|
|||
|
|
Write-Host ""
|
|||
|
|
Write-Host "Next patch will hard-wire the correct module path once you paste the existing local start command/log line."
|
|||
|
|
exit 1
|
|||
|
|
|