The custom regex manager matched all nextcloud_image entries with the same depName, causing Renovate to bump all matrix entries (NC 31, 32, 33) to the latest version instead of only the targeted major. Fix by capturing nextcloud_version to create version-specific dep names (nextcloud-31, nextcloud-32, nextcloud-33) with allowedVersions rules constraining each to its own major. Also pins docker-compose.yml to 32.x and removes redundant inline # renovate: comments that could cause duplicate matching. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
222 lines
8.1 KiB
YAML
222 lines
8.1 KiB
YAML
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@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.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
|
|
needs: [linting]
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
- name: Install the latest version of uv
|
|
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.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:
|
|
nextcloud_version:
|
|
- "31"
|
|
- "32"
|
|
# - "33" # Disabled until all upstream apps support NC 33
|
|
mode:
|
|
- "single-user"
|
|
- "multi-user-basic"
|
|
- "oauth"
|
|
- "login-flow"
|
|
include:
|
|
# Version-specific image pins — Renovate updates these via customManagers in renovate.json
|
|
# Each entry is pinned to its major version (e.g., NC 31 only gets 31.x updates)
|
|
- nextcloud_version: "31"
|
|
nextcloud_image: "docker.io/library/nextcloud:31.0.14@sha256:9bf3fae91aad4dca3eff02c1f71df8d5c6705a349065fb537aa5c5ef578f1013"
|
|
- nextcloud_version: "32"
|
|
nextcloud_image: "docker.io/library/nextcloud:32.0.6@sha256:5c4e09f72f096cd68379a8ae69f71e61d13da5a07430fc4a17c702a14e6a4267"
|
|
# Disabled until all upstream apps support NC 33
|
|
# - nextcloud_version: "33"
|
|
# nextcloud_image: "docker.io/library/nextcloud:33.0.0@sha256:d53f6cb35b0712aa890a5e4a8ca21043d6fcd390f38c55b710816dd7cbc2edc0"
|
|
|
|
# Mode-specific properties
|
|
- mode: single-user
|
|
profile: single-user
|
|
markers: "(smoke and not oauth and not keycloak and not login_flow and not multi_user_basic) or (integration and not oauth and not keycloak and not login_flow and not multi_user_basic)"
|
|
wait-port: 8000
|
|
mcp-internal-url: "http://mcp:8000"
|
|
needs-playwright: false
|
|
extra-args: >-
|
|
--ignore=tests/integration/test_qdrant_collection_creation.py
|
|
--ignore=tests/rag_evaluation/
|
|
|
|
- mode: multi-user-basic
|
|
profile: multi-user-basic
|
|
markers: "multi_user_basic"
|
|
wait-port: 8003
|
|
mcp-internal-url: "http://mcp-multi-user-basic:8000"
|
|
needs-playwright: true
|
|
extra-args: ""
|
|
|
|
- mode: oauth
|
|
profile: oauth
|
|
markers: "oauth and not keycloak"
|
|
wait-port: 8001
|
|
mcp-internal-url: "http://mcp-oauth:8001"
|
|
needs-playwright: true
|
|
extra-args: ""
|
|
|
|
- mode: login-flow
|
|
profile: login-flow
|
|
markers: "login_flow"
|
|
wait-port: 8004
|
|
mcp-internal-url: "http://mcp-login-flow:8004"
|
|
needs-playwright: true
|
|
extra-args: ""
|
|
|
|
name: integration (${{ matrix.mode }} / nc${{ matrix.nextcloud_version }})
|
|
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
submodules: 'true'
|
|
|
|
- name: Set up PHP 8.4
|
|
if: matrix.mode != 'single-user'
|
|
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # 2.36.0
|
|
with:
|
|
php-version: 8.4
|
|
coverage: none
|
|
|
|
# OIDC app installed from app store (dev mount removed from docker-compose.yml)
|
|
|
|
- name: Set up Node.js
|
|
if: matrix.mode != 'single-user'
|
|
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
|
with:
|
|
node-version: 24
|
|
|
|
- name: Build Astrolabe app
|
|
if: matrix.mode != 'single-user'
|
|
run: |
|
|
cd third_party/astrolabe
|
|
composer install --no-dev --optimize-autoloader
|
|
npm ci
|
|
npm run build
|
|
|
|
- name: Build OIDC app
|
|
run: |
|
|
cd third_party/oidc
|
|
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"
|
|
env:
|
|
MCP_SERVER_URL: ${{ matrix.mcp-internal-url }}
|
|
NEXTCLOUD_IMAGE: ${{ matrix.nextcloud_image }}
|
|
|
|
- name: Install the latest version of uv
|
|
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.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 -sSf http://localhost:8080/status.php 2>/dev/null | grep -q '"installed":true'; 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.mode == 'oauth' || matrix.mode == 'login-flow'
|
|
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: Collect service logs on failure
|
|
if: failure()
|
|
run: |
|
|
docker compose --profile ${{ matrix.profile }} logs --tail=500 > /tmp/docker-compose-logs.txt 2>&1
|
|
docker compose exec -T app cat /var/www/html/data/nextcloud.log 2>/dev/null | tail -100 > /tmp/nextcloud-app.log 2>&1 || true
|
|
|
|
- name: Upload debug artifacts
|
|
if: failure()
|
|
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
|
|
with:
|
|
name: debug-${{ matrix.mode }}-nc${{ matrix.nextcloud_version }}
|
|
path: |
|
|
/tmp/*.png
|
|
/tmp/docker-compose-logs.txt
|
|
/tmp/nextcloud-app.log
|
|
retention-days: 7
|
|
if-no-files-found: ignore
|