Skip to content

feat(mono): +billing providers #5306

feat(mono): +billing providers

feat(mono): +billing providers #5306

# File: .github/workflows/validate.yml
# Workflow: v0.7.1 – Changes (Validate)
name: v0.7.1 - Changes (Validate)
on:
pull_request:
paths:
- 'pkgs/**'
workflow_dispatch:
jobs:
detect-changed-files:
if: ${{ !cancelled() }}
runs-on: [testing]
outputs:
matrix: ${{ steps.detect.outputs.matrix }}
steps:
# ──────────────────────────────────────────────────────────────────────────
# Step: Check out code ─ (uses: actions/checkout@v4)
# ──────────────────────────────────────────────────────────────────────────
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0 # fetch full history for diffing
# ──────────────────────────────────────────────────────────────────────────
# Step: Get changed files (id=files)
# ──────────────────────────────────────────────────────────────────────────
- name: Get changed files
id: files
run: |
set -eo pipefail
echo "Collecting changed files …"
git diff --name-only \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}" > changed_files.txt
cat changed_files.txt
# ──────────────────────────────────────────────────────────────────────────
# Step: Detect changes and generate package matrix (id=detect)
# Function: find_pyproject_root (Bash function)
# ──────────────────────────────────────────────────────────────────────────
- name: Detect changes and generate test matrix
id: detect
run: |
echo "Detecting changed packages …"
# Exclude the monorepo root pyproject.toml as it does not represent
# a real package and will always fail validation.
CHANGED_FILES=$(grep '^pkgs/' changed_files.txt | grep -v '^pkgs/pyproject.toml$' || true)
if [ -z "$CHANGED_FILES" ]; then
echo "No changes in pkgs/. Exiting."
echo 'matrix=[]' >> "$GITHUB_OUTPUT"
exit 0
fi
declare -A PACKAGE_SET # <package_path> ⇒ 1
# ── Function: find_pyproject_root ────────────────────────────────────
find_pyproject_root() {
local path="$1"
while true; do
[[ -f "$path/pyproject.toml" ]] && { echo "$path"; return; }
[[ "$path" == "." ]] && { echo ""; return; }
path="$(dirname "$path")"
done
}
# ─────────────────────────────────────────────────────────────────────
for FILE in $CHANGED_FILES; do
DIR=$(dirname "$FILE")
PKG_ROOT=$(find_pyproject_root "$DIR")
if [[ -z "$PKG_ROOT" || "$PKG_ROOT" == "pkgs" ]]; then
continue
fi
PKG_PATH="${PKG_ROOT#pkgs/}" # strip leading pkgs/
PACKAGE_SET["$PKG_PATH"]=1 # record the package
done
# Build JSON matrix
MATRIX="["
for PKG in "${!PACKAGE_SET[@]}"; do
MATRIX+='{"package_path":"'"$PKG"'","tests":""},'
done
MATRIX="${MATRIX%,}]"
echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT"
echo "Final test matrix: $MATRIX"
# ─────────────────────────────────────────────────────────────────────────────
# Job: run-tests – executes once per package reported in matrix
# ─────────────────────────────────────────────────────────────────────────────
run-tests:
needs: detect-changed-files
if: ${{ !cancelled() && needs.detect-changed-files.outputs.matrix != '[]' }}
runs-on: [testing]
strategy:
fail-fast: false
matrix:
package_tests: ${{ fromJSON(needs.detect-changed-files.outputs.matrix) }}
env:
UNIQUE_VENV_PATH: "${{ github.workspace }}/.venv_core_${{ github.run_id }}"
steps:
# ────────────────────────────────────────────────────────────────────────
# Step: Check out code ─ (uses: actions/checkout@v4)
# ────────────────────────────────────────────────────────────────────────
- name: Check out code
uses: actions/checkout@v4
# ────────────────────────────────────────────────────────────────────────
# Step: Set up Python ─ (uses: actions/setup-python@v5)
# ────────────────────────────────────────────────────────────────────────
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
# ────────────────────────────────────────────────────────────────────────
# Step: Create & activate venv
# ────────────────────────────────────────────────────────────────────────
- name: Create and activate virtual environment
run: |
python -m venv "$UNIQUE_VENV_PATH"
source "$UNIQUE_VENV_PATH/bin/activate"
# ────────────────────────────────────────────────────────────────────────
# Step: Install dependencies
# ────────────────────────────────────────────────────────────────────────
- name: Install dependencies
run: |
source "$UNIQUE_VENV_PATH/bin/activate"
python -m pip install --upgrade pip
pip install uv poetry toml
# ────────────────────────────────────────────────────────────────────────
# Step: Ruff Format (package_path only)
# ────────────────────────────────────────────────────────────────────────
- name: Ruff Format
run: |
source "$UNIQUE_VENV_PATH/bin/activate"
PKG_PATH="${{ matrix.package_tests.package_path }}"
echo "Running ruff format on pkgs/$PKG_PATH"
cd pkgs
PACKAGE_NAME=$(python -c "import toml, pathlib, sys; print(toml.load(pathlib.Path('$PKG_PATH')/'pyproject.toml')['project']['name'])")
uv run --directory "$PKG_PATH" --package "$PACKAGE_NAME" --isolated --active ruff format .
# ────────────────────────────────────────────────────────────────────────
# Step: Ruff Check (package_path only)
# ────────────────────────────────────────────────────────────────────────
- name: Ruff Check
run: |
source "$UNIQUE_VENV_PATH/bin/activate"
PKG_PATH="${{ matrix.package_tests.package_path }}"
echo "Running ruff check on pkgs/$PKG_PATH"
cd pkgs
PACKAGE_NAME=$(python -c "import toml, pathlib, sys; print(toml.load(pathlib.Path('$PKG_PATH')/'pyproject.toml')['project']['name'])")
uv run --directory "$PKG_PATH" --package "$PACKAGE_NAME" --isolated --active ruff check . --fix
# ────────────────────────────────────────────────────────────────────────
# Step: Run Pytests (run all tests in package)
# ────────────────────────────────────────────────────────────────────────
- name: Run Pytests
run: |
set -o pipefail
source "$UNIQUE_VENV_PATH/bin/activate"
PKG_PATH="${{ matrix.package_tests.package_path }}"
echo "Running pytest in pkgs/$PKG_PATH"
cd pkgs
PACKAGE_NAME=$(python -c "import toml, pathlib, sys; print(toml.load(pathlib.Path('$PKG_PATH')/'pyproject.toml')['project']['name'])")
export PKG_PATH PACKAGE_NAME
set +e
uv run --directory "$PKG_PATH" --package "$PACKAGE_NAME" --isolated --active pytest -vvv | tee pytest.log
STATUS=${PIPESTATUS[0]}
set -e
python - <<'PY'
import os, re, pathlib
pkg_name = os.environ.get("PACKAGE_NAME", "unknown")
pkg_path = os.environ.get("PKG_PATH", "")
log = pathlib.Path('pytest.log').read_text().splitlines()[-1]
patterns = {
'passed': r'(\d+) passed',
'failed': r'(\d+) failed',
'xfailed': r'(\d+) xfailed',
'xpassed': r'(\d+) xpassed',
'skipped': r'(\d+) skipped',
'warnings': r'(\d+) warnings?',
'errors': r'(\d+) errors?'
}
counts = {k: 0 for k in patterns}
for key, pat in patterns.items():
m = re.search(pat, log)
if m:
counts[key] = int(m.group(1))
summary = " ".join(f"{k}={v}" for k, v in counts.items())
print(f"::notice title=pytest summary ({pkg_name})::pkg_path={pkg_path} {summary}")
PY
exit $STATUS