name: Tests on: pull_request: branches: - master jobs: linting: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install the latest version of uv uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 - name: Check format run: uv run --frozen ruff format --diff - name: Linting run: uv run --frozen ruff check - name: Type check run: uv run --frozen ty check -- nextcloud_mcp_server unit-test: runs-on: ubuntu-latest steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install the latest version of uv uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 - name: Run unit tests run: uv run pytest -v -m unit -o "addopts=-p no:asyncio" integration-test: runs-on: ubuntu-latest needs: [linting] strategy: fail-fast: false matrix: include: - mode: single-user profile: single-user markers: "(smoke and not oauth and not keycloak and not login_flow) or (integration and not oauth and not keycloak and not login_flow)" wait-port: 8000 needs-playwright: false extra-args: >- --ignore=tests/integration/test_multi_user_basic_auth.py --ignore=tests/integration/test_qdrant_collection_creation.py --ignore=tests/rag_evaluation/ # NOTE: Playwright browser tests are skipped in CI (no browser grant flow). # These entries still run non-Playwright tests marked with the same markers. - mode: oauth profile: oauth markers: "oauth and not keycloak" wait-port: 8001 needs-playwright: true extra-args: "" - mode: login-flow profile: login-flow markers: "login_flow" wait-port: 8004 needs-playwright: true extra-args: "" name: integration (${{ matrix.mode }}) steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: submodules: 'true' # Build OIDC app (only needed for oauth/login-flow modes) - name: Set up PHP 8.4 if: matrix.needs-playwright uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0 with: php-version: 8.4 coverage: none - name: Install OIDC app composer dependencies if: matrix.needs-playwright run: | cd third_party/oidc composer install --no-dev - name: Set up Node.js uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: 22 - name: Build Astrolabe app run: | cd third_party/astrolabe composer install --no-dev --optimize-autoloader npm ci npm run build # Start services with the appropriate profile - name: Run docker compose uses: hoverkraft-tech/compose-action@4894d2492015c1774ee5a13a95b1072093087ec3 # v2.5.0 with: compose-file: "./docker-compose.yml" compose-flags: "--profile ${{ matrix.profile }}" up-flags: "--build" - name: Install the latest version of uv uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0 - name: Install Playwright if: matrix.needs-playwright run: uv run playwright install chromium --with-deps # Wait for Nextcloud to be healthy - name: Wait for Nextcloud run: | echo "Waiting for Nextcloud at http://localhost:8080..." max_attempts=60 attempt=0 until curl -o /dev/null -s -w "%{http_code}\n" http://localhost:8080/ocs/v2.php/apps/serverinfo/api/v1/info | grep -q "401"; do attempt=$((attempt + 1)) if [ $attempt -ge $max_attempts ]; then echo "Nextcloud did not become ready in time." docker compose logs app exit 1 fi echo "Attempt $attempt/$max_attempts: Not ready, sleeping 5s..." sleep 5 done echo "Nextcloud is ready." # Wait for the MCP service to be healthy - name: Wait for MCP service (${{ matrix.mode }}) run: | echo "Waiting for MCP service on port ${{ matrix.wait-port }}..." max_attempts=30 attempt=0 until curl -o /dev/null -s -w "%{http_code}\n" http://localhost:${{ matrix.wait-port }}/health 2>/dev/null | grep -qE "200|404|405"; do attempt=$((attempt + 1)) if [ $attempt -ge $max_attempts ]; then echo "MCP service did not become ready in time." docker compose --profile ${{ matrix.profile }} logs exit 1 fi echo "Attempt $attempt/$max_attempts: Not ready, sleeping 5s..." sleep 5 done echo "MCP service is ready on port ${{ matrix.wait-port }}." - name: Verify OIDC configuration if: matrix.needs-playwright run: | echo "=== OIDC Discovery ===" curl -s http://localhost:8080/.well-known/openid-configuration | jq . echo "=== OIDC App Status ===" docker compose exec -T app php occ app:list --output=json 2>/dev/null | jq '.enabled.oidc // "NOT INSTALLED"' - name: Run tests (${{ matrix.mode }}) env: NEXTCLOUD_HOST: "http://localhost:8080" NEXTCLOUD_USERNAME: "admin" NEXTCLOUD_PASSWORD: "admin" run: | uv run pytest -v \ --log-cli-level=WARN \ -m '${{ matrix.markers }}' \ -o "addopts=-p no:asyncio" \ --timeout=300 \ ${{ matrix.extra-args }} - name: Report skipped Playwright tests if: matrix.needs-playwright run: | echo "::notice::Playwright browser tests are skipped in CI. Run locally with: uv run pytest -m '${{ matrix.markers }}' --browser firefox" uv run pytest --collect-only -q \ -m '${{ matrix.markers }}' \ ${{ matrix.extra-args }} 2>/dev/null \ | tail -1 || true - name: Show service logs on failure if: failure() run: docker compose --profile ${{ matrix.profile }} logs --tail=100