mirror of
https://github.com/kellymichels/zscripts-token-savers
synced 2026-10-07 07:18:18 +00:00
The mirror carries the tagOnDeploy feature, its tests, and the zstart gitPull fix from the private tree. Twelve published references to current product names and internal issue numbers are reworded generically, the denylist learns the current spellings (a dot or hyphen broke the word, an underscore hid the boundary), and planted cases prove the suite now sees them. CHECKSUMS.txt regenerated. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
232 lines
9.4 KiB
PowerShell
232 lines
9.4 KiB
PowerShell
# Evomedia.net Token Savers — https://github.com/evomedia-net/evo.zscripts
|
|
# Created by Kelly Michels · dev@evomedia.net
|
|
# Licensed under the MIT License. See LICENSE.
|
|
# Version: v1.0.0.0.23
|
|
|
|
# zstart.ps1 — start local dev servers for any project defined in zconfig.json.
|
|
#
|
|
# Usage:
|
|
# zstart <project> [<project> ...] [-Port N] [-BindHost host] [-Detached]
|
|
#
|
|
# Examples:
|
|
# zstart pyapp
|
|
# zstart viteapp -Port 3000
|
|
# zstart pyapp nextapp -Detached
|
|
#
|
|
# Handlers by kind: python (python -m <startModule>, or uvicorn <startApp> for
|
|
# ASGI/FastAPI apps; prefers .venv), vite (npm run dev -- --host --port),
|
|
# nextjs (npm run dev with PORT).
|
|
#
|
|
param(
|
|
[Parameter(Position = 0, ValueFromRemainingArguments = $true)]
|
|
[string[]]$Projects = @(),
|
|
[Alias("p")][int]$Port = 0,
|
|
[string]$BindHost = "127.0.0.1",
|
|
[switch]$Detached
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
. (Join-Path $PSScriptRoot "ZHelpers.ps1")
|
|
Start-ZTracking
|
|
|
|
if ($Projects.Count -eq 0) {
|
|
$keys = (Get-ZProjectKeys) -join ', '
|
|
Write-Host ""
|
|
Write-Host "Usage: zstart <project> [<project> ...] [-Port N] [-Detached] [-BindHost host]" -ForegroundColor Yellow
|
|
Write-Host " Projects in zconfig.json: $keys" -ForegroundColor Gray
|
|
Stop-ZTracking; exit 1
|
|
}
|
|
|
|
function Test-PortNeedsAdmin {
|
|
param([int]$ListenPort)
|
|
if ($ListenPort -ge 1024) { return }
|
|
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
|
if (-not $isAdmin) {
|
|
Write-Host "WARNING: Port $ListenPort requires Administrator privileges to bind. Run this shell as Administrator!" -ForegroundColor Red
|
|
}
|
|
}
|
|
|
|
function Start-PythonProject {
|
|
param([string]$Key, $Proj, [int]$ListenPort, [bool]$RunDetached, [string]$HostBind = "127.0.0.1")
|
|
$root = $Proj.localRoot
|
|
if (-not (Test-Path -LiteralPath $root)) { throw "Project root not found: $root" }
|
|
$module = $Proj.startModule
|
|
$app = $Proj.startApp
|
|
if (-not $module -and -not $app) {
|
|
throw "Project '$Key' (kind=python) needs 'startModule' (python -m ...) or 'startApp' (uvicorn app:app) in zconfig.json."
|
|
}
|
|
Set-Location -LiteralPath $root
|
|
$venvPython = Join-Path $root ".venv\Scripts\python.exe"
|
|
$usingVenv = Test-Path -LiteralPath $venvPython
|
|
$exe = if ($usingVenv) { $venvPython } else { "python" }
|
|
|
|
# Optional convention: if the project ships scripts/build_version_tool.py,
|
|
# bump (or at least read) the build version on every dev start.
|
|
$buildVersion = ""
|
|
$versionTool = Join-Path $root "scripts\build_version_tool.py"
|
|
if (Test-Path -LiteralPath $versionTool) {
|
|
try {
|
|
$bumpOut = & $exe $versionTool bump 2>$null
|
|
if ($LASTEXITCODE -eq 0 -and $bumpOut) {
|
|
$buildVersion = ($bumpOut | Select-Object -Last 1).ToString().Trim()
|
|
}
|
|
} catch { }
|
|
if ([string]::IsNullOrWhiteSpace($buildVersion)) {
|
|
try {
|
|
$getOut = & $exe $versionTool get 2>$null
|
|
if ($LASTEXITCODE -eq 0 -and $getOut) {
|
|
$buildVersion = ($getOut | Select-Object -Last 1).ToString().Trim()
|
|
}
|
|
} catch { }
|
|
}
|
|
}
|
|
|
|
# startApp (uvicorn ASGI target, e.g. app.main:app) takes precedence over
|
|
# startModule (python -m ...). uvicorn runs via the venv python's -m, and
|
|
# gets zstart's bind-host + dev port.
|
|
if ($app) {
|
|
$runArgs = @("-m", "uvicorn", $app, "--host", $HostBind, "--port", "$ListenPort", "--reload")
|
|
$what = "uvicorn $app"
|
|
} else {
|
|
$runArgs = @("-m", $module)
|
|
$what = "python -m $module"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "=== zstart ($($Proj.label)) ===" -ForegroundColor Cyan
|
|
if (-not $usingVenv) {
|
|
Write-Host "No project venv at $root\.venv - using system 'python' (its deps may be missing)." -ForegroundColor Yellow
|
|
Write-Host " Create one: python -m venv .venv; .\.venv\Scripts\pip install -e ." -ForegroundColor DarkGray
|
|
}
|
|
Write-Host "Starting $what on port $ListenPort..." -ForegroundColor Cyan
|
|
if (-not [string]::IsNullOrWhiteSpace($buildVersion)) {
|
|
Write-Host "Build Version: $buildVersion" -ForegroundColor Magenta
|
|
}
|
|
|
|
Show-ProjectMotd -Root $root -BuildVersion $buildVersion
|
|
|
|
Write-Host "Press Ctrl+C to stop the server" -ForegroundColor DarkGray
|
|
Test-PortNeedsAdmin -ListenPort $ListenPort
|
|
Write-Host ""
|
|
|
|
if ($RunDetached) {
|
|
Start-Process -FilePath $exe -ArgumentList $runArgs -WorkingDirectory $root | Out-Null
|
|
Write-Host "Started in detached mode." -ForegroundColor Green
|
|
Write-Host "Use zkill $Key to stop it." -ForegroundColor DarkGray
|
|
} else {
|
|
& $exe @runArgs
|
|
}
|
|
}
|
|
|
|
function Start-ViteProject {
|
|
param([string]$Key, $Proj, [int]$ListenPort, [string]$HostBind, [bool]$RunDetached)
|
|
$root = $Proj.localRoot
|
|
if (-not (Test-Path -LiteralPath $root)) { throw "Project root not found: $root" }
|
|
if (-not (Test-Path -LiteralPath (Join-Path $root "package.json"))) {
|
|
throw "package.json not found in $root"
|
|
}
|
|
Set-Location -LiteralPath $root
|
|
|
|
Write-Host ""
|
|
Write-Host "=== zstart ($($Proj.label) - Vite) ===" -ForegroundColor Cyan
|
|
Write-Host "Directory: $root" -ForegroundColor DarkGray
|
|
Write-Host "URL: http://${HostBind}:$ListenPort/" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
if (-not (Test-Path -LiteralPath (Join-Path $root "node_modules"))) {
|
|
Write-Host "node_modules missing - running npm install..." -ForegroundColor Yellow
|
|
& npm install
|
|
if ($LASTEXITCODE -ne 0) { throw "npm install failed with exit $LASTEXITCODE" }
|
|
}
|
|
|
|
Show-ProjectMotd -Root $root
|
|
|
|
Write-Host "Press Ctrl+C to stop the dev server" -ForegroundColor DarkGray
|
|
Test-PortNeedsAdmin -ListenPort $ListenPort
|
|
Write-Host ""
|
|
|
|
$npmArgs = @("run", "dev", "--", "--host", $HostBind, "--port", "$ListenPort")
|
|
if ($RunDetached) {
|
|
Start-Process -FilePath "npm" -ArgumentList $npmArgs -WorkingDirectory $root -WindowStyle Normal | Out-Null
|
|
Write-Host "Started npm run dev in a new window (detached)." -ForegroundColor Green
|
|
Write-Host "Use zkill $Key to free port $ListenPort." -ForegroundColor DarkGray
|
|
} else {
|
|
& npm @npmArgs
|
|
}
|
|
}
|
|
|
|
function Start-NextProject {
|
|
param([string]$Key, $Proj, [int]$ListenPort, [bool]$RunDetached)
|
|
$root = $Proj.localRoot
|
|
if (-not (Test-Path -LiteralPath $root)) { throw "Project root not found: $root" }
|
|
if (-not (Test-Path -LiteralPath (Join-Path $root "package.json"))) {
|
|
throw "package.json not found in $root"
|
|
}
|
|
Set-Location -LiteralPath $root
|
|
|
|
Write-Host ""
|
|
Write-Host "=== zstart ($($Proj.label) - Next.js) ===" -ForegroundColor Cyan
|
|
Write-Host "Starting on port $ListenPort..." -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
Show-ProjectMotd -Root $root
|
|
|
|
Write-Host "Press Ctrl+C to stop the server" -ForegroundColor DarkGray
|
|
Test-PortNeedsAdmin -ListenPort $ListenPort
|
|
Write-Host ""
|
|
|
|
$env:PORT = "$ListenPort"
|
|
if ($RunDetached) {
|
|
Start-Process -FilePath "npm" -ArgumentList "run", "dev" -WorkingDirectory $root | Out-Null
|
|
Write-Host "Started in detached mode on port $ListenPort." -ForegroundColor Green
|
|
Write-Host "Use zkill $Key to stop it." -ForegroundColor DarkGray
|
|
} else {
|
|
npm run dev
|
|
}
|
|
}
|
|
|
|
# Optional per-project pre-start steps from zconfig.json:
|
|
# "start": { "gitPull": true, "env": { "SOME_FLAG": "1" } }
|
|
# gitPull runs 'git pull --ff-only' in the project root; env sets process
|
|
# environment variables before the server starts.
|
|
function Invoke-ProjectStartPrep {
|
|
param($Proj)
|
|
if (-not $Proj.start) { return }
|
|
if ($Proj.start.env) {
|
|
foreach ($item in $Proj.start.env.PSObject.Properties) {
|
|
Set-Item -Path "Env:$($item.Name)" -Value ([string]$item.Value)
|
|
Write-Host " env $($item.Name)=$($item.Value)" -ForegroundColor DarkGray
|
|
}
|
|
}
|
|
if ($Proj.start.gitPull) {
|
|
# Never lets a pull stand between the user and a running server: the
|
|
# helper reports, it does not throw (#130). The inline version this
|
|
# replaced aborted on git's ordinary stderr progress under Stop.
|
|
$pull = Invoke-StartGitPull -Root $Proj.localRoot
|
|
if ($pull.Ok) {
|
|
Write-Host " git pull: $($pull.Message)" -ForegroundColor DarkGray
|
|
} else {
|
|
Write-Host " Auto-pull skipped - starting with the current checkout. ($($pull.Message); set start.gitPull=false to stop trying)" -ForegroundColor Yellow
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($key in $Projects) {
|
|
$proj = Get-ZProject -Key $key
|
|
$devPort = if ($Port -gt 0) { $Port } elseif ($proj.ports -and $proj.ports.dev) { [int]$proj.ports.dev } else { 3000 }
|
|
|
|
Invoke-ProjectStartPrep -Proj $proj
|
|
|
|
switch ([string]$proj.kind) {
|
|
"python" { Start-PythonProject -Key $key -Proj $proj -ListenPort $devPort -HostBind $BindHost -RunDetached $Detached.IsPresent }
|
|
"vite" { Start-ViteProject -Key $key -Proj $proj -ListenPort $devPort -HostBind $BindHost -RunDetached $Detached.IsPresent }
|
|
"nextjs" { Start-NextProject -Key $key -Proj $proj -ListenPort $devPort -RunDetached $Detached.IsPresent }
|
|
default {
|
|
Write-Host ""
|
|
Write-Host "Project '$key' has kind '$($proj.kind)' - no local dev server to start." -ForegroundColor Yellow
|
|
Write-Host "Supported kinds for zstart: python, vite, nextjs" -ForegroundColor Gray
|
|
}
|
|
}
|
|
}
|
|
Stop-ZTracking
|