Files
Jyotisha/deploy/ci-python-venv.sh
T
ClaudeandClaude Opus 5.5 a84ebff6e4
Independent Staging Quality Gate / validate-python (push) Successful in 17m4s
Independent Staging Quality Gate / validate-frontend (push) Successful in 23m50s
Independent Staging Quality Gate / publish (push) Successful in 5m38s
ci: run the Python and frontend gates in parallel and keep install caches on the runner
- Split `validate` into `validate-python` and `validate-frontend`; publish
  needs both. Runner capacity is >= 2 (publish and migrate already overlap).
- deploy/ci-python-venv.sh: venv kept under /root/.cache keyed by Python
  version, ISO week, pins and requirements; persistent pip cache. A fresh
  venv per run spent ~3 min re-downloading the same wheels.
- npm ci gets a persistent download cache and --prefer-offline (every one
  of 1,010 packages was a cache miss).
- publish builds and pushes the API and web images concurrently; the web
  Dockerfile mounts BuildKit caches for npm and .next/cache.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DbBXoyn7Hj3LCW3BUs5bZ8
2026-11-03 16:59:57 +08:00

62 lines
1.9 KiB
Bash
Executable File

#!/usr/bin/env bash
# Quality-gate Python environment, reused across runs on the self-hosted runner.
#
# act_runner's hostexecutor throws the workspace away after every job but keeps
# the host filesystem. Rebuilding .venv from scratch cost ~3 minutes per job,
# most of it re-downloading the same large wheels (timezonefinder 55 MB,
# pyjhora 34 MB). The venv now lives under CI_CACHE_ROOT, keyed by everything
# that decides its contents, and the workspace gets a `.venv` symlink to it.
#
# The key includes the ISO week: requirements.txt still has unpinned entries,
# so a weekly rebuild keeps picking up upstream releases the way a fresh venv
# per run used to. A venv is only used once `.complete` exists; a crashed build
# is removed and rebuilt under the lock.
set -euo pipefail
CI_CACHE_ROOT="${CI_CACHE_ROOT:-/root/.cache}"
VENV_ROOT="$CI_CACHE_ROOT/jyotisha-venvs"
export PIP_CACHE_DIR="${PIP_CACHE_DIR:-$CI_CACHE_ROOT/jyotisha-pip}"
pins=(
"mcp==1.28.1"
"pydantic==2.13.4"
"numpy==2.5.1"
"pandas==2.3.3"
"timezonefinder==8.2.5"
)
key="$(
{
python3 --version
date -u +%G-W%V
printf '%s\n' "${pins[@]}"
cat requirements.txt requirements-dev.txt
} | sha256sum | cut -c1-16
)"
venv="$VENV_ROOT/$key"
mkdir -p "$VENV_ROOT" "$PIP_CACHE_DIR"
exec 8>"$VENV_ROOT/.lock"
flock -w 1200 8
if [ ! -f "$venv/.complete" ]; then
echo "building quality-gate venv $key"
rm -rf -- "$venv"
python3 -m venv --clear "$venv"
"$venv/bin/python" -m pip install --upgrade pip
"$venv/bin/python" -m pip install "${pins[@]}" -r requirements.txt -r requirements-dev.txt
touch "$venv/.complete"
else
echo "reusing quality-gate venv $key"
fi
touch "$venv"
# Drop venvs no run has used for a week; the one just selected is fresh.
find "$VENV_ROOT" -mindepth 1 -maxdepth 1 -type d -mtime +7 -exec rm -rf -- {} +
flock -u 8
exec 8>&-
rm -rf -- .venv
ln -s "$venv" .venv
.venv/bin/python -c 'import swisseph, pytest'
.venv/bin/ruff --version
.venv/bin/python --version