Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions .github/workflows/v0.8.0_validate_changed_files.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# File: .github/workflows/validate.yml
# Workflow: v0.8.0 – Changes (Validate)

name: v0.8.0 - Changes (Validate)

on:
pull_request:
paths:
- 'pkgs/**'
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
detect-changed-files:
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: ${{ 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: |
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'])")
uv run --directory "$PKG_PATH" --package "$PACKAGE_NAME" --isolated --active pytest -vvv