diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8764169..da2301b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,10 +3,6 @@ name: CI on: pull_request: branches: [main, dev] - push: - branches: [main, dev] - tags: ["v*.*.*"] - merge_group: concurrency: group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -17,33 +13,8 @@ permissions: env: PYTHON_VERSION: "3.11" - LOCAL_API_IMAGE_AMD64: code-interpreter:ci-amd64 - LOCAL_API_IMAGE_ARM64: code-interpreter:ci-arm64 jobs: - changes: - runs-on: ubuntu-latest - outputs: - runtime: ${{ steps.filter.outputs.runtime }} - container: ${{ steps.filter.outputs.container }} - steps: - - uses: actions/checkout@v4 - - - id: filter - uses: dorny/paths-filter@v3 - with: - filters: | - runtime: - - 'Dockerfile' - - 'docker/requirements/**' - container: - - 'Dockerfile' - - 'docker/**' - - 'src/**' - - 'dashboard/**' - - 'requirements.txt' - - 'docker-compose.yml' - static: runs-on: ubuntu-latest steps: @@ -91,48 +62,9 @@ jobs: pip install pytest pytest-asyncio pytest-cov pytest-mock - name: Run unit tests - run: | - mkdir -p test-results - pytest tests/unit/ --junitxml=test-results/unit.xml - - - name: Upload unit results - if: always() - uses: actions/upload-artifact@v4 - with: - name: unit-results - path: test-results/ - if-no-files-found: ignore - - integration-contract: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip + run: pytest tests/unit/ - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Run contract integration tests - run: | - mkdir -p test-results - pytest tests/integration/ -m contract_only --junitxml=test-results/integration-contract.xml - - - name: Upload contract integration results - if: always() - uses: actions/upload-artifact@v4 - with: - name: integration-contract-results - path: test-results/ - if-no-files-found: ignore - - integration-core: + integration: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -148,259 +80,5 @@ jobs: pip install -r requirements.txt pip install pytest pytest-asyncio pytest-cov pytest-mock - - name: Run core integration tests - run: | - mkdir -p test-results - pytest tests/integration/ -m "not contract_only" --junitxml=test-results/integration-core.xml - - - name: Upload core integration results - if: always() - uses: actions/upload-artifact@v4 - with: - name: integration-core-results - path: test-results/ - if-no-files-found: ignore - - build-app-amd64: - needs: [changes] - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v4 - - - uses: docker/setup-buildx-action@v3 - - - name: Build amd64 app candidate - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_AMD64}" \ - --cache-from "type=gha,scope=app-amd64" \ - --cache-to "type=gha,scope=app-amd64,mode=max" \ - . - - - name: Inspect amd64 image - run: docker image inspect "${LOCAL_API_IMAGE_AMD64}" >/dev/null - - functional-smoke-amd64: - needs: [changes] - runs-on: ubuntu-24.04 - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build local amd64 test image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_AMD64}" \ - --cache-from "type=gha,scope=app-amd64" \ - --cache-to "type=gha,scope=app-amd64,mode=max" \ - . - - - name: Start live stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_AMD64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run live smoke tests - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest tests/functional/ \ - -m "live_api and not slow and not client_replay" \ - -v \ - --junitxml=test-results/functional-smoke-amd64.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > compose-amd64.log - - - name: Upload functional smoke artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: functional-smoke-amd64 - path: | - test-results/ - compose-amd64.log - if-no-files-found: ignore - - - name: Stop live stack - if: always() - run: docker compose down -v - - client-replay-amd64: - needs: [changes] - runs-on: ubuntu-24.04 - timeout-minutes: 45 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build local amd64 replay image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_AMD64}" \ - --cache-from "type=gha,scope=app-amd64" \ - --cache-to "type=gha,scope=app-amd64,mode=max" \ - . - - - name: Start live stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_AMD64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run client replay tests - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest tests/functional/ \ - -m client_replay \ - -v \ - --junitxml=test-results/client-replay-amd64.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > compose-client-replay.log - - - name: Upload client replay artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: client-replay-amd64 - path: | - test-results/ - compose-client-replay.log - if-no-files-found: ignore - - - name: Stop live stack - if: always() - run: docker compose down -v - - arm64-smoke-conditional: - if: needs.changes.outputs.container == 'true' - needs: [changes] - runs-on: ubuntu-24.04-arm - timeout-minutes: 35 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build local arm64 test image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_ARM64}" \ - --cache-from "type=gha,scope=app-arm64" \ - --cache-to "type=gha,scope=app-arm64,mode=max" \ - . - - - name: Start live stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_ARM64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run arm64 smoke suite - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest \ - tests/functional/test_health.py \ - tests/functional/test_exec_workflow.py::TestSessionWorkflow::test_execution_creates_session \ - tests/functional/test_files.py::TestFileUpload::test_upload_single_file \ - tests/functional/test_ptc.py::TestPTCInitialExecution::test_ptc_simple_code_completes \ - -v \ - --junitxml=test-results/arm64-smoke.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > compose-arm64.log - - - name: Upload arm64 smoke artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: arm64-smoke - path: | - test-results/ - compose-arm64.log - if-no-files-found: ignore - - - name: Stop live stack - if: always() - run: docker compose down -v + - name: Run integration tests + run: pytest tests/integration/ diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml deleted file mode 100644 index e598c08..0000000 --- a/.github/workflows/nightly.yml +++ /dev/null @@ -1,232 +0,0 @@ -name: Nightly Validation - -on: - schedule: - - cron: '23 4 * * *' - workflow_dispatch: - -concurrency: - group: nightly-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -env: - PYTHON_VERSION: "3.11" - LOCAL_API_IMAGE_AMD64: code-interpreter:nightly-amd64 - LOCAL_API_IMAGE_ARM64: code-interpreter:nightly-arm64 - -jobs: - full-live-amd64: - runs-on: ubuntu-24.04 - timeout-minutes: 75 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build nightly amd64 image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_AMD64}" \ - --cache-from "type=gha,scope=nightly-app-amd64" \ - --cache-to "type=gha,scope=nightly-app-amd64,mode=max" \ - . - - - name: Start nightly stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_AMD64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run full live functional suite - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest tests/functional/ -m live_api -v --junitxml=test-results/nightly-full-live-amd64.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > nightly-full-amd64.log - - - name: Upload nightly full artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: nightly-full-live-amd64 - path: | - test-results/ - nightly-full-amd64.log - if-no-files-found: ignore - - - name: Stop nightly stack - if: always() - run: docker compose down -v - - slow-live-amd64: - runs-on: ubuntu-24.04 - timeout-minutes: 75 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build nightly amd64 image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_AMD64}" \ - --cache-from "type=gha,scope=nightly-app-amd64" \ - --cache-to "type=gha,scope=nightly-app-amd64,mode=max" \ - . - - - name: Start nightly stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_AMD64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run slow live suite - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest tests/functional/ -m slow -v --junitxml=test-results/nightly-slow-live-amd64.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > nightly-slow-amd64.log - - - name: Upload nightly slow artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: nightly-slow-live-amd64 - path: | - test-results/ - nightly-slow-amd64.log - if-no-files-found: ignore - - - name: Stop nightly stack - if: always() - run: docker compose down -v - - arm64-smoke: - runs-on: ubuntu-24.04-arm - timeout-minutes: 40 - steps: - - uses: actions/checkout@v4 - - - uses: actions/setup-python@v6 - with: - python-version: ${{ env.PYTHON_VERSION }} - cache: pip - - - uses: docker/setup-buildx-action@v3 - - - name: Install test dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements.txt - pip install pytest pytest-asyncio pytest-cov pytest-mock - - - name: Build nightly arm64 image - run: | - docker buildx build \ - --load \ - --target app \ - --tag "${LOCAL_API_IMAGE_ARM64}" \ - --cache-from "type=gha,scope=nightly-app-arm64" \ - --cache-to "type=gha,scope=nightly-app-arm64,mode=max" \ - . - - - name: Start nightly arm64 stack - env: - API_IMAGE: ${{ env.LOCAL_API_IMAGE_ARM64 }} - run: | - cp .env.example .env - docker compose up -d - - - name: Wait for API - run: | - if ! scripts/ci/wait_for_api.sh http://localhost:8000/health 24 5; then - docker compose logs --no-color api - exit 1 - fi - - - name: Run nightly arm64 smoke suite - env: - API_BASE: http://localhost:8000 - API_KEY: your-secure-api-key-here-change-this-in-production - run: | - mkdir -p test-results - pytest \ - tests/functional/test_health.py \ - tests/functional/test_exec_workflow.py::TestSessionWorkflow::test_execution_creates_session \ - tests/functional/test_files.py::TestFileUpload::test_upload_single_file \ - tests/functional/test_ptc.py::TestPTCInitialExecution::test_ptc_simple_code_completes \ - -v \ - --junitxml=test-results/nightly-arm64-smoke.xml - - - name: Capture compose logs on failure - if: failure() - run: docker compose logs --no-color > nightly-arm64.log - - - name: Upload nightly arm64 artifacts - if: always() - uses: actions/upload-artifact@v4 - with: - name: nightly-arm64-smoke - path: | - test-results/ - nightly-arm64.log - if-no-files-found: ignore - - - name: Stop nightly arm64 stack - if: always() - run: docker compose down -v diff --git a/requirements.txt b/requirements.txt index 694e1cb..c8c1ac0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ requests>=2.31.0,<3 # Core API framework -fastapi==0.129.0 -uvicorn[standard]==0.41.0 +fastapi==0.135.2 +uvicorn[standard]==0.42.0 # Data validation and serialization pydantic==2.12.5 @@ -11,7 +11,7 @@ pydantic-settings==2.13.1 httpx==0.28.1 # Redis for session management -redis==7.2.0 +redis==7.4.0 # SQLite async support for metrics aiosqlite>=0.19.0 @@ -24,9 +24,9 @@ python-dateutil==2.9.0.post0 # Testing framework -pytest==9.0.2 +pytest==9.0.3 pytest-asyncio==1.3.0 -pytest-cov==4.1.0 +pytest-cov==7.1.0 pytest-mock==3.15.1 # Development tools @@ -35,7 +35,7 @@ flake8==7.3.0 mypy==1.19.1 # Environment management -python-dotenv==1.2.1 +python-dotenv==1.2.2 # Logging structlog==25.5.0