#!/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