From 32da8b5fd025061753367348ff96bb3b6ada56ba Mon Sep 17 00:00:00 2001 From: Killian Larcher <98161034+KillianLarcher@users.noreply.github.com> Date: Wed, 10 Jun 2026 18:08:58 +0200 Subject: [PATCH] feat: externalize e2e testings [skip-release] (#312) * feat: externalize e2e tests. * refactor: improve e2e workflow. * chore: upgrade workflow action version. * fix: createEnv by adding emptyStringAsUndefined (#317) * chore: release 1.18.2 --------- Co-authored-by: killian-larcher Co-authored-by: Charles GTE Co-authored-by: github-actions[bot] --- .github/workflows/e2e.yml | 163 +++++++++++++++----------------------- CITATION.cff | 2 +- package.json | 2 +- src/env.mjs | 2 + tsconfig.json | 3 +- 5 files changed, 72 insertions(+), 100 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index fb7f9707..111ab795 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -4,114 +4,83 @@ on: pull_request: branches: [main] +permissions: + contents: read + packages: write + jobs: - build-and-test: + build-image: runs-on: ubuntu-latest if: github.event.pull_request.head.repo.full_name == github.repository + outputs: + image: ${{ steps.image.outputs.ref }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - - name: Setup pnpm - uses: pnpm/action-setup@v4 + - name: Compute image reference + id: image + run: echo "ref=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/portabase:${GITHUB_SHA}" >> "$GITHUB_OUTPUT" - - name: Setup Node.js - uses: actions/setup-node@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 with: - node-version: 22 - cache: 'pnpm' + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Install dependencies - run: pnpm install --frozen-lockfile - - - name: Build Docker image + - name: Build and push Docker image uses: docker/build-push-action@v6 with: context: . file: ./docker/dockerfile/Dockerfile - push: false - load: true - tags: portabase/portabase:test + push: true + tags: ${{ steps.image.outputs.ref }} + target: prod - - name: Run app container - run: | - docker run -d --name myapp \ - -p 8887:80 \ - -e NODE_ENV=production \ - -e PROJECT_URL=http://localhost:8887 \ - -e PROJECT_SECRET=80af5e4c875dfded3a6ba511c6ed8b0160cad723f848ee0851403ed6141f6ba1 \ - portabase/portabase:test - - - name: Wait for app port to be listening - run: | - for i in {1..40}; do - - if curl -fsS http://localhost:8887/ >/dev/null; then - echo "App is responding on port 8887" - exit 0 - fi - echo "Waiting for app readiness... ($i/40)" - sleep 2 - done - echo "Timeout: app never became ready" - docker logs myapp - exit 1 - - - name: Install Playwright browsers - run: pnpm exec playwright install --with-deps chromium - - - name: Run Playwright tests - run: pnpm exec playwright test - env: - PROJECT_URL: http://localhost:8887 - # E2E Notification - E2E_NOTIFICATION_SMTP_HOST: ${{ secrets.E2E_NOTIFICATION_SMTP_HOST }} - E2E_NOTIFICATION_SMTP_PORT: ${{ secrets.E2E_NOTIFICATION_SMTP_PORT }} - E2E_NOTIFICATION_SMTP_USER: ${{ secrets.E2E_NOTIFICATION_SMTP_USER }} - E2E_NOTIFICATION_SMTP_PASSWORD: ${{ secrets.E2E_NOTIFICATION_SMTP_PASSWORD }} - E2E_NOTIFICATION_SMTP_FROM: ${{ secrets.E2E_NOTIFICATION_SMTP_FROM }} - E2E_NOTIFICATION_SMTP_TO: ${{ secrets.E2E_NOTIFICATION_SMTP_TO }} - E2E_NOTIFICATION_SLACK_WEBHOOK: ${{ secrets.E2E_NOTIFICATION_SLACK_WEBHOOK }} - E2E_NOTIFICATION_DISCORD_WEBHOOK: ${{ secrets.E2E_NOTIFICATION_DISCORD_WEBHOOK }} - E2E_NOTIFICATION_TELEGRAM_BOT_TOKEN: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_BOT_TOKEN }} - E2E_NOTIFICATION_TELEGRAM_CHAT_ID: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_CHAT_ID }} - E2E_NOTIFICATION_TELEGRAM_TOPIC_ID: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_TOPIC_ID }} - E2E_NOTIFICATION_GOTIFY_SERVER_URL: ${{ secrets.E2E_NOTIFICATION_GOTIFY_SERVER_URL }} - E2E_NOTIFICATION_GOTIFY_APP_TOKEN: ${{ secrets.E2E_NOTIFICATION_GOTIFY_APP_TOKEN }} - E2E_NOTIFICATION_NTFY_TOPIC: ${{ secrets.E2E_NOTIFICATION_NTFY_TOPIC }} - E2E_NOTIFICATION_NTFY_SERVER_URL: ${{ secrets.E2E_NOTIFICATION_NTFY_SERVER_URL }} - E2E_NOTIFICATION_NTFY_TOKEN: ${{ secrets.E2E_NOTIFICATION_NTFY_TOKEN }} - E2E_NOTIFICATION_NTFY_USERNAME: ${{ secrets.E2E_NOTIFICATION_NTFY_USERNAME }} - E2E_NOTIFICATION_NTFY_PASSWORD: ${{ secrets.E2E_NOTIFICATION_NTFY_PASSWORD }} - E2E_NOTIFICATION_WEBHOOK_URL: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_URL }} - E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER }} - E2E_NOTIFICATION_WEBHOOK_SECRET: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_SECRET }} - - # E2E Storage - E2E_STORAGE_AWS_S3_ENDPOINT_URL: ${{ secrets.E2E_STORAGE_AWS_S3_ENDPOINT_URL }} - E2E_STORAGE_AWS_S3_REGION: ${{ secrets.E2E_STORAGE_AWS_S3_REGION }} - E2E_STORAGE_AWS_S3_ACCESS_KEY: ${{ secrets.E2E_STORAGE_AWS_S3_ACCESS_KEY }} - E2E_STORAGE_AWS_S3_SECRET_KEY: ${{ secrets.E2E_STORAGE_AWS_S3_SECRET_KEY }} - E2E_STORAGE_AWS_S3_BUCKET_NAME: ${{ secrets.E2E_STORAGE_AWS_S3_BUCKET_NAME }} - E2E_STORAGE_AWS_S3_PORT: ${{ secrets.E2E_STORAGE_AWS_S3_PORT }} - E2E_STORAGE_R2_ENDPOINT_URL: ${{ secrets.E2E_STORAGE_R2_ENDPOINT_URL }} - E2E_STORAGE_R2_REGION: ${{ secrets.E2E_STORAGE_R2_REGION }} - E2E_STORAGE_R2_ACCESS_KEY: ${{ secrets.E2E_STORAGE_R2_ACCESS_KEY }} - E2E_STORAGE_R2_SECRET_KEY: ${{ secrets.E2E_STORAGE_R2_SECRET_KEY }} - E2E_STORAGE_R2_BUCKET_NAME: ${{ secrets.E2E_STORAGE_R2_BUCKET_NAME }} - E2E_STORAGE_R2_PORT: ${{ secrets.E2E_STORAGE_R2_PORT }} - E2E_STORAGE_GOOGLE_DRIVE_CLIENT_ID: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_CLIENT_ID }} - E2E_STORAGE_GOOGLE_DRIVE_CLIENT_SECRET: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_CLIENT_SECRET }} - E2E_STORAGE_GOOGLE_DRIVE_FOLDER_ID: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_FOLDER_ID }} - - - name: Upload report if failed - if: failure() - uses: actions/upload-artifact@v4 - with: - name: playwright-report - path: playwright-report/ - retention-days: 7 - - - name: Cleanup - if: always() - run: docker stop myapp && docker rm myapp || true \ No newline at end of file + run-e2e: + if: github.event.pull_request.head.repo.full_name == github.repository + needs: build-image + uses: portabase/e2e-tests/.github/workflows/run-e2e.yml@main + with: + server_image: ${{ needs.build-image.outputs.image }} + secrets: + E2E_NOTIFICATION_SMTP_HOST: ${{ secrets.E2E_NOTIFICATION_SMTP_HOST }} + E2E_NOTIFICATION_SMTP_PORT: ${{ secrets.E2E_NOTIFICATION_SMTP_PORT }} + E2E_NOTIFICATION_SMTP_USER: ${{ secrets.E2E_NOTIFICATION_SMTP_USER }} + E2E_NOTIFICATION_SMTP_PASSWORD: ${{ secrets.E2E_NOTIFICATION_SMTP_PASSWORD }} + E2E_NOTIFICATION_SMTP_FROM: ${{ secrets.E2E_NOTIFICATION_SMTP_FROM }} + E2E_NOTIFICATION_SMTP_TO: ${{ secrets.E2E_NOTIFICATION_SMTP_TO }} + E2E_NOTIFICATION_SLACK_WEBHOOK: ${{ secrets.E2E_NOTIFICATION_SLACK_WEBHOOK }} + E2E_NOTIFICATION_DISCORD_WEBHOOK: ${{ secrets.E2E_NOTIFICATION_DISCORD_WEBHOOK }} + E2E_NOTIFICATION_TELEGRAM_BOT_TOKEN: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_BOT_TOKEN }} + E2E_NOTIFICATION_TELEGRAM_CHAT_ID: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_CHAT_ID }} + E2E_NOTIFICATION_TELEGRAM_TOPIC_ID: ${{ secrets.E2E_NOTIFICATION_TELEGRAM_TOPIC_ID }} + E2E_NOTIFICATION_GOTIFY_SERVER_URL: ${{ secrets.E2E_NOTIFICATION_GOTIFY_SERVER_URL }} + E2E_NOTIFICATION_GOTIFY_APP_TOKEN: ${{ secrets.E2E_NOTIFICATION_GOTIFY_APP_TOKEN }} + E2E_NOTIFICATION_NTFY_TOPIC: ${{ secrets.E2E_NOTIFICATION_NTFY_TOPIC }} + E2E_NOTIFICATION_NTFY_SERVER_URL: ${{ secrets.E2E_NOTIFICATION_NTFY_SERVER_URL }} + E2E_NOTIFICATION_NTFY_TOKEN: ${{ secrets.E2E_NOTIFICATION_NTFY_TOKEN }} + E2E_NOTIFICATION_NTFY_USERNAME: ${{ secrets.E2E_NOTIFICATION_NTFY_USERNAME }} + E2E_NOTIFICATION_NTFY_PASSWORD: ${{ secrets.E2E_NOTIFICATION_NTFY_PASSWORD }} + E2E_NOTIFICATION_WEBHOOK_URL: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_URL }} + E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_SECRET_HEADER }} + E2E_NOTIFICATION_WEBHOOK_SECRET: ${{ secrets.E2E_NOTIFICATION_WEBHOOK_SECRET }} + E2E_STORAGE_AWS_S3_ENDPOINT_URL: ${{ secrets.E2E_STORAGE_AWS_S3_ENDPOINT_URL }} + E2E_STORAGE_AWS_S3_REGION: ${{ secrets.E2E_STORAGE_AWS_S3_REGION }} + E2E_STORAGE_AWS_S3_ACCESS_KEY: ${{ secrets.E2E_STORAGE_AWS_S3_ACCESS_KEY }} + E2E_STORAGE_AWS_S3_SECRET_KEY: ${{ secrets.E2E_STORAGE_AWS_S3_SECRET_KEY }} + E2E_STORAGE_AWS_S3_BUCKET_NAME: ${{ secrets.E2E_STORAGE_AWS_S3_BUCKET_NAME }} + E2E_STORAGE_AWS_S3_PORT: ${{ secrets.E2E_STORAGE_AWS_S3_PORT }} + E2E_STORAGE_R2_ENDPOINT_URL: ${{ secrets.E2E_STORAGE_R2_ENDPOINT_URL }} + E2E_STORAGE_R2_REGION: ${{ secrets.E2E_STORAGE_R2_REGION }} + E2E_STORAGE_R2_ACCESS_KEY: ${{ secrets.E2E_STORAGE_R2_ACCESS_KEY }} + E2E_STORAGE_R2_SECRET_KEY: ${{ secrets.E2E_STORAGE_R2_SECRET_KEY }} + E2E_STORAGE_R2_BUCKET_NAME: ${{ secrets.E2E_STORAGE_R2_BUCKET_NAME }} + E2E_STORAGE_R2_PORT: ${{ secrets.E2E_STORAGE_R2_PORT }} + E2E_STORAGE_GOOGLE_DRIVE_CLIENT_ID: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_CLIENT_ID }} + E2E_STORAGE_GOOGLE_DRIVE_CLIENT_SECRET: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_CLIENT_SECRET }} + E2E_STORAGE_GOOGLE_DRIVE_FOLDER_ID: ${{ secrets.E2E_STORAGE_GOOGLE_DRIVE_FOLDER_ID }} diff --git a/CITATION.cff b/CITATION.cff index 07f8b374..cd4a56a3 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -33,5 +33,5 @@ keywords: - web-ui - agent license: Apache-2.0 -version: 1.18.1 +version: 1.18.2 date-released: '2026-03-02' diff --git a/package.json b/package.json index 0c3d4fae..f61be9c9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "portabase", - "version": "1.18.1", + "version": "1.18.2", "private": true, "scripts": { "dev": "next dev --turbopack -p 8887", diff --git a/src/env.mjs b/src/env.mjs index 46155d10..e0c09d92 100644 --- a/src/env.mjs +++ b/src/env.mjs @@ -6,6 +6,7 @@ import packageJson from "../package.json" with {type: "json"}; const {version} = packageJson; export const env = createEnv({ + emptyStringAsUndefined: true, server: { NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(), @@ -199,3 +200,4 @@ export const env = createEnv({ }, }); + diff --git a/tsconfig.json b/tsconfig.json index 877b650f..a8f9c637 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,7 +33,8 @@ "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", - ".next/dev/types/**/*.ts" + ".next/dev/types/**/*.ts", + ".next/dev/dev/types/**/*.ts" ], "exclude": [ "node_modules"