feat: standardized offline A/B benchmark template for feature validation #121
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI - PR Checks | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| jobs: | |
| # Detect if PR contains code changes (skip expensive checks for docs-only PRs) | |
| check-code-changes: | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| outputs: | |
| has_code_changes: ${{ steps.filter.outputs.code }} | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| - name: Check for code changes | |
| uses: dorny/paths-filter@v4 | |
| id: filter | |
| with: | |
| filters: | | |
| code: | |
| - '!docs/**' | |
| - '!**/*.md' | |
| - '!LICENSE' | |
| - '!OWNERS' | |
| # Lint: runs all pre-commit hooks (ruff, shellcheck, hadolint, markdownlint, yamllint, etc.) | |
| lint: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Run pre-commit | |
| uses: pre-commit/action@v3.0.1 | |
| # Require VERSION bump when code changes | |
| version-check: | |
| runs-on: ubuntu-latest | |
| needs: check-code-changes | |
| if: needs.check-code-changes.outputs.has_code_changes == 'true' | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check VERSION was bumped | |
| run: | | |
| changed=$(git diff --name-only origin/main...HEAD \ | |
| | grep -E '^(common|prediction|training)/' \ | |
| | grep -vE 'requirements\.(in|txt)$' \ | |
| | grep -v 'Dockerfile$' || true) | |
| if [ -z "$changed" ]; then | |
| echo "No source changes in common/, prediction/, or training/. Skipping version check." | |
| exit 0 | |
| fi | |
| echo "Source files changed:" | |
| echo "$changed" | |
| if ! git diff --name-only origin/main...HEAD | grep -q '^VERSION$'; then | |
| echo "::error::Source changes detected but VERSION was not bumped. Please update the VERSION file." | |
| exit 1 | |
| fi | |
| new_version=$(cat VERSION) | |
| old_version=$(git show origin/main:VERSION 2>/dev/null || echo "0.0.0") | |
| if [ "$new_version" = "$old_version" ]; then | |
| echo "::error::VERSION file was modified but the version ($new_version) is the same as main." | |
| exit 1 | |
| fi | |
| highest=$(printf '%s\n%s\n' "$old_version" "$new_version" | sort -V | tail -n1) | |
| if [ "$highest" != "$new_version" ]; then | |
| echo "::error::VERSION ($new_version) is not greater than main ($old_version)." | |
| exit 1 | |
| fi | |
| echo "VERSION bumped: $old_version -> $new_version" | |
| # Verify the restructured layout is importable | |
| import-check: | |
| runs-on: ubuntu-latest | |
| needs: check-code-changes | |
| if: needs.check-code-changes.outputs.has_code_changes == 'true' | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| # find_spec instead of import_module: prediction_server.py creates | |
| # /local_models at import time (ModelSyncer.__init__), which fails | |
| # outside a container. Switch to import_module after the lifespan refactor. | |
| - name: Check imports | |
| run: | | |
| pip install -r requirements.txt --quiet | |
| python -c " | |
| import importlib.util | |
| for mod in ['prediction.prediction_server', 'training.training_server', 'common.types']: | |
| spec = importlib.util.find_spec(mod) | |
| assert spec is not None, f'{mod} not found' | |
| print(f'{mod}: {spec.origin}') | |
| " | |
| # Container: build (no push) to validate all service Dockerfiles | |
| container-build: | |
| runs-on: ubuntu-latest | |
| needs: check-code-changes | |
| if: needs.check-code-changes.outputs.has_code_changes == 'true' | |
| strategy: | |
| matrix: | |
| service: | |
| - name: prediction | |
| dockerfile: prediction/Dockerfile | |
| - name: training | |
| dockerfile: training/Dockerfile | |
| - name: test | |
| dockerfile: tests/Dockerfile | |
| steps: | |
| - name: Checkout source | |
| uses: actions/checkout@v6 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Build ${{ matrix.service.name }} container (no push) | |
| run: | | |
| docker buildx build \ | |
| --platform linux/amd64 \ | |
| -f ${{ matrix.service.dockerfile }} \ | |
| --tag test-build-${{ matrix.service.name }}:pr-${{ github.event.pull_request.number }} \ | |
| . |