diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 000000000..0a658d644 --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,145 @@ +name: E2E (overlay on nightly) + +# Builds the Node.js example app, overlays it onto the published +# ghcr.io/euro-office/documentserver:nightly image, and runs the DocumentServer +# Playwright e2e suite against it. The suite drives /example/, so a change here +# is directly exercised without rebuilding the rest of the stack. +on: + push: + branches: + - main + - develop + - 'release/**' + - 'hotfix/**' + pull_request: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + NIGHTLY_IMAGE: ghcr.io/euro-office/documentserver:nightly + OVERLAY_IMAGE: euro-office/documentserver:e2e-example + +jobs: + e2e: + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Check out document-server-integration + uses: actions/checkout@v4 + with: + path: dsi + + # The nodejs example embeds public/** into the pkg binary and requires + # document-formats/onlyoffice-docs-formats.json at startup; it also serves + # "new" files from document-templates. Both are submodules — init just the + # nodejs example's assets (not all languages') so the binary isn't missing + # them at runtime. + - name: Init nodejs example asset submodules + working-directory: dsi + run: | + git submodule update --init --depth 1 \ + web/documentserver-example/nodejs/public/assets/document-formats \ + web/documentserver-example/nodejs/public/assets/document-templates \ + web/documentserver-example/nodejs/public/assets/plugin-aiautofill + + # The e2e suite lives in the DocumentServer repo. Prefer a same-named + # branch (so tests can be co-developed with the change), else main. + - name: Check out DocumentServer e2e (current branch) + id: docserver + uses: actions/checkout@v4 + continue-on-error: true + with: + repository: Euro-Office/DocumentServer + path: documentserver + ref: ${{ github.head_ref || github.ref_name }} + - name: Check out DocumentServer e2e (main) + if: steps.docserver.outcome != 'success' + uses: actions/checkout@v4 + with: + repository: Euro-Office/DocumentServer + path: documentserver + ref: main + + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + + # Mirrors example.bake.Dockerfile: install deps, then pkg the app. + - name: Build example app + working-directory: dsi/web/documentserver-example/nodejs + run: | + npm install -g @yao-pkg/pkg + npm install + mkdir -p "${{ github.workspace }}/deploy" + pkg . -t linux-x64 --node-options="--max_old_space_size=4096" -o "${{ github.workspace }}/deploy/example" + + - name: Pull nightly image + run: docker pull ${{ env.NIGHTLY_IMAGE }} + + - name: Build overlay image with fresh example binary + run: | + set -euo pipefail + cat > overlay.Dockerfile <<'EOF' + ARG NIGHTLY_IMAGE + FROM ${NIGHTLY_IMAGE} + COPY example /tmp/example + # documentserver-example sits next to the documentserver root + # (/var/www//documentserver-example); locate it via the sdkjs dir. + RUN set -eux; \ + root="$(dirname "$(find /var/www -maxdepth 5 -type d -name sdkjs -path '*documentserver*' | head -n1)")"; \ + test -n "$root"; \ + install -m0755 /tmp/example "${root}-example/example"; \ + rm -f /tmp/example + EOF + docker build \ + --build-arg NIGHTLY_IMAGE=${{ env.NIGHTLY_IMAGE }} \ + -t ${{ env.OVERLAY_IMAGE }} \ + -f overlay.Dockerfile \ + deploy + + - name: Install e2e dependencies + working-directory: documentserver/e2e + run: npm ci + + - name: Install Playwright browsers + working-directory: documentserver/e2e + run: npx playwright install chromium --with-deps + + - name: Run E2E tests + working-directory: documentserver/e2e + env: + E2E_IMAGE: ${{ env.OVERLAY_IMAGE }} + run: npm test + + # On failure, boot the overlay image standalone and dump the example + # process logs so the real startup error is visible in CI (the e2e + # harness removes its own container on teardown). + - name: Diagnose example startup (on failure) + if: failure() + run: | + set -uo pipefail + docker rm -f dsi-diag >/dev/null 2>&1 || true + docker run -d --name dsi-diag -p 8997:80 -e EXAMPLE_ENABLED=true ${{ env.OVERLAY_IMAGE }} + for i in $(seq 1 30); do + code=$(curl -s -o /dev/null -w '%{http_code}' http://localhost:8997/example/ || true) + echo "t=$((i*3))s /example/ -> $code"; [ "$code" = "200" ] && break; sleep 3 + done + echo "=== supervisor status ==="; docker exec dsi-diag supervisorctl status || true + echo "=== ds-example_err.log ===" + docker exec dsi-diag sh -c 'cat /var/log/*/*/ds-example_err.log 2>/dev/null | tail -60' || true + echo "=== ds-example_out.log ===" + docker exec dsi-diag sh -c 'cat /var/log/*/*/ds-example_out.log 2>/dev/null | tail -30' || true + docker rm -f dsi-diag >/dev/null 2>&1 || true + + - name: Upload Playwright report + if: always() + uses: actions/upload-artifact@v4 + with: + name: playwright-report-${{ github.sha }} + path: documentserver/e2e/playwright-report/ + retention-days: 14