diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3ff9713 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: + push: + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + cpu-tests: + name: CPU tests (Python ${{ matrix.python }}) + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python: ['3.10', '3.12'] + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 + with: + python-version: ${{ matrix.python }} + cache: pip + cache-dependency-path: requirements-ci.txt + - name: Install CPU test environment + run: | + python -m pip install -r requirements-ci.txt + python -m pip install torch==2.7.0 --index-url https://download.pytorch.org/whl/cpu + python -m pip install --no-deps -e . + - name: Run CPU regression suite + run: bash scripts/test_cpu_ci.sh + - name: Upload test report + if: always() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: cpu-tests-python-${{ matrix.python }} + path: reports/cpu-tests.xml + if-no-files-found: warn + retention-days: 14 + + ci-required: + name: CI required + if: always() + needs: [cpu-tests] + runs-on: ubuntu-latest + timeout-minutes: 2 + steps: + - name: Require all CPU test jobs to pass + env: + RESULT: ${{ needs.cpu-tests.result }} + run: test "$RESULT" = success diff --git a/docs/ci.md b/docs/ci.md new file mode 100644 index 0000000..27ee604 --- /dev/null +++ b/docs/ci.md @@ -0,0 +1,37 @@ +# Continuous integration and merge policy + +Pushes to any branch and pull requests targeting `main` run `.github/workflows/ci.yml`. +The workflow can also be started manually from GitHub Actions. + +The CPU regression suite runs on Python 3.10 and 3.12 with PyTorch 2.7.0 CPU. +It covers configuration, asynchronous execution, phase tracing, reload control, +legacy and cost-aware CMLFQ, rollout clients, and CPU-offload backend orchestration. +The explicit test list lives in `scripts/test_cpu_ci.sh`; add new CPU-safe tests there. +This is a selected regression suite, not the entire repository test suite. + +To reproduce in a clean Python 3.10–3.12 virtual environment: + +```bash +python -m pip install -r requirements-ci.txt +python -m pip install torch==2.7.0 --index-url https://download.pytorch.org/whl/cpu +python -m pip install --no-deps -e . +bash scripts/test_cpu_ci.sh +``` + +JUnit reports are uploaded for 14 days. Jobs have timeouts and superseded runs +are cancelled. `CI required` succeeds only when every matrix job passes; +failed, cancelled, or skipped dependencies do not satisfy the gate. +No path filters are used, so documentation-only PRs also receive the required check. +PR workflows use read-only permissions, hosted runners, and no cluster credentials. + +The `main` branch protection requires a PR and the GitHub Actions `CI required` +check on an up-to-date branch, including administrators. Force pushes and deletion +are disabled. No reviewer approval is required by this initial policy; a maintainer +still merges manually after checks pass. GitHub branch protection is repository +configuration, separate from this workflow file; changing YAML alone does not +activate it. This setup does not publish packages or deploy training services. + +CUDA kernel, vLLM connector, multi-GPU KV migration, and full RL throughput +validation remain manual cluster tests using `scripts/validate_cpu_offload.slurm` +and `scripts/benchmark_scheduler_rl.slurm`. CPU CI does not certify GPU correctness +or performance. Public PR code is not automatically executed on HPC-GMC. diff --git a/requirements-ci.txt b/requirements-ci.txt new file mode 100644 index 0000000..36bfd40 --- /dev/null +++ b/requirements-ci.txt @@ -0,0 +1,6 @@ +# CPU-only CI dependencies; intentionally excludes the CUDA runtime stack. +pytest==8.3.5 +pytest-asyncio==0.26.0 +numpy==1.26.4 +PyYAML==6.0.2 +httpx==0.28.1 diff --git a/scripts/test_cpu_ci.sh b/scripts/test_cpu_ci.sh new file mode 100644 index 0000000..d13d0a4 --- /dev/null +++ b/scripts/test_cpu_ci.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")/.." +python -m pytest -q --strict-markers --junitxml=reports/cpu-tests.xml \ + tests/test_config_parsing.py \ + tests/test_qwen3_config.py \ + tests/test_async_task_runner.py \ + tests/test_phase_tracer.py \ + tests/test_restartable_vllm_server.py \ + tests/test_cmlfq_scheduler.py \ + tests/test_cmlfq_cost_scheduler.py \ + tests/test_hetero_cmlfq_integration.py \ + tests/test_rollout_engine.py \ + tests/test_cpu_offload_backend.py