-
-
Notifications
You must be signed in to change notification settings - Fork 0
fix(ci): run E2E Mongo as single-node replica set (fixes P2031) #495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
angeloreale
wants to merge
17
commits into
dev
Choose a base branch
from
angeloreale-fix/e2e-mongo-replica-set
base: dev
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
d3269ba
docs(plans): fold Projects + task deep links into phase 5, shared /@ …
angeloreale 1e31a1f
feat(db): add Project model, list public-profile fields, task job pos…
angeloreale 39cf453
feat(services): project service, task applications, public list seria…
angeloreale 4f8780c
feat(api): public tasklists, job apply flow, projects routes
angeloreale 2a57677
feat(ui): public list/job/project pages, job board, forms, task deep …
angeloreale d967b10
feat(i18n): Phase 5 key groups in en.json, openapi sync, lint cleanups
angeloreale 4c77f1b
feat(ledger): DPIP off-chain ledger, dual-mode transfers, wallet life…
angeloreale be74323
feat(orgs): organizations as first-class owners with shared /@ handles
angeloreale 8d5dd81
feat(events): events core — Event model, pages, RSVP, list/project links
angeloreale ea1627a
feat(ar/ds): adding e2e tests
angeloreale aa8fe54
test(e2e): Playwright suite + CI merge gate; fixes found by the tests
angeloreale 4a37f62
fix(ar/ci): e2e checks
angeloreale e8861c3
fix(ar/ci): e2e checks
angeloreale 028f3c2
feat(ar/ds): adding e2e tests
angeloreale 0dea84d
fix(ci): run E2E Mongo as single-node replica set (fixes P2031)
angeloreale 4d34a12
fix(ci): remove ::error:: workflow command annotation from secrets check
Copilot c46480c
fix(ci): remove secrets check step that logged secret names to stdout
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,178 @@ | ||
| name: E2E | ||
|
|
||
| # Merge gate for dev: the whole-stack smoke + user journey must pass. | ||
| # Required repo secrets (GitHub → Settings → Secrets and variables → Actions): | ||
| # CLERK_SECRET_KEY — Clerk backend key (DEVELOPMENT instance) | ||
| # NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY — the app's publishable key | ||
| # | ||
| # DB: a fresh MongoDB container per run, started as a SINGLE-NODE REPLICA SET. | ||
| # A standalone mongod is not enough: Prisma wraps nested writes in a | ||
| # transaction, so even `prisma.user.create({ include: { profiles: true } })` in | ||
| # `ensureUserAndProfile` fails with P2031 ("requires your MongoDB server to be | ||
| # run as a replica set") — no User row is ever created and every downstream | ||
| # request 404s with "User not found". `services:` cannot pass `--replSet` to | ||
| # the container's command, so Mongo is started with `docker run` instead. | ||
| # | ||
| # Running a replica set also means CI exercises the SAME ledger path as | ||
| # production (single interactive `prisma.$transaction`) rather than the | ||
| # standalone sequential fallback, so the dual-mode deviation is covered where | ||
| # it actually ships. | ||
| # | ||
| # `prisma db push` alone reproduces the current schema; the 0021–0028 data | ||
| # migrations are all no-ops on an empty DB (their backfills/repairs only touch | ||
| # legacy rows, which never exist here), so they are not run. The harness | ||
| # self-seeds the SYSTEM:treasury wallet. | ||
|
|
||
| on: | ||
| # Every PR gets E2E — the stacked phase PRs target each other, not dev; | ||
| # only the bottom PR's check can be made required for the dev merge. | ||
| pull_request: | ||
| push: | ||
| branches: [dev] | ||
|
|
||
| concurrency: | ||
| group: e2e-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| MONGO_IMAGE: mongo:7 | ||
| MONGO_REPLICA_SET: rs0 | ||
|
|
||
| jobs: | ||
| e2e: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 60 | ||
| # Clerk secrets are not exposed to pull requests from forks, so the suite | ||
| # cannot run there. Skip instead of failing red on every fork PR. | ||
| if: >- | ||
| github.event_name != 'pull_request' || | ||
| github.event.pull_request.head.repo.full_name == github.repository | ||
| env: | ||
| # `replicaSet=rs0` makes the driver do topology discovery and mark the | ||
| # deployment transaction-capable; without it Prisma still sees a | ||
| # standalone topology and refuses to open a transaction. | ||
| DATABASE_URL: mongodb://localhost:27017/e2e?replicaSet=rs0 | ||
| CLERK_SECRET_KEY: ${{ secrets.CLERK_SECRET_KEY }} | ||
| NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }} | ||
| CLERK_PUBLISHABLE_KEY: ${{ secrets.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY }} | ||
| INTERNAL_FETCH_SECRET: e2e-internal-secret | ||
| NEXT_PUBLIC_BASE_URL: http://localhost:3000 | ||
| # The replica set is real here, so the ledger must take the transactional | ||
| # path — never silently degrade to the dev fallback in CI. | ||
| LEDGER_REQUIRE_TRANSACTIONS: 'true' | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: Start MongoDB (single-node replica set) | ||
| run: | | ||
| set -euo pipefail | ||
| docker run -d --name mongo -p 27017:27017 "$MONGO_IMAGE" \ | ||
| --replSet "$MONGO_REPLICA_SET" --bind_ip_all | ||
|
|
||
| echo "Waiting for mongod to accept connections..." | ||
| for i in $(seq 1 60); do | ||
| if docker exec mongo mongosh --quiet --eval 'db.adminCommand({ ping: 1 })' >/dev/null 2>&1; then | ||
| break | ||
| fi | ||
| if [ "$i" -eq 60 ]; then | ||
| echo "::error::mongod did not become reachable"; docker logs mongo; exit 1 | ||
| fi | ||
| sleep 2 | ||
| done | ||
|
|
||
| # `host: localhost:27017` is what the driver on the runner is told to | ||
| # connect to during topology discovery, and the container publishes | ||
| # that port on the host — so the advertised member address is | ||
| # reachable from both inside and outside the container. | ||
| docker exec mongo mongosh --quiet --eval " | ||
| try { | ||
| rs.status() | ||
| } catch (e) { | ||
| rs.initiate({ _id: '$MONGO_REPLICA_SET', members: [{ _id: 0, host: 'localhost:27017' }] }) | ||
| }" | ||
|
|
||
| echo "Waiting for PRIMARY..." | ||
| for i in $(seq 1 60); do | ||
| if docker exec mongo mongosh --quiet --eval 'db.hello().isWritablePrimary' 2>/dev/null | grep -q true; then | ||
| echo "Replica set $MONGO_REPLICA_SET is PRIMARY" | ||
| break | ||
| fi | ||
| if [ "$i" -eq 60 ]; then | ||
| echo "::error::replica set never reached PRIMARY"; docker logs mongo; exit 1 | ||
| fi | ||
| sleep 2 | ||
| done | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 20 | ||
| cache: npm | ||
|
|
||
| - name: Prepare env | ||
| run: cp .env.public .env | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci --legacy-peer-deps | ||
|
|
||
| - name: Generate Prisma client | ||
| run: npx prisma generate | ||
|
|
||
| # Fails in 2 seconds with a clear message instead of burying the run in | ||
| # hundreds of P2031 stack traces. Mirrors `supportsTransactions()`. | ||
| - name: Verify the database supports transactions | ||
| run: | | ||
| node -e " | ||
| const { PrismaClient } = require('./generated/prisma/client') | ||
| const prisma = new PrismaClient() | ||
| prisma.\$runCommandRaw({ hello: 1 }) | ||
| .then(async (hello) => { | ||
| await prisma.\$disconnect() | ||
| if (!hello.setName) { | ||
| console.error('DATABASE_URL does not point at a replica set (hello.setName is empty).') | ||
| console.error('Prisma needs transactions for nested writes (P2031); the suite cannot pass.') | ||
| process.exit(1) | ||
| } | ||
| console.log('Replica set OK:', hello.setName, '| primary:', hello.isWritablePrimary) | ||
| }) | ||
| .catch((error) => { console.error(error); process.exit(1) }) | ||
| " | ||
|
|
||
| - name: Push schema (indexes/collections) | ||
| run: npx prisma db push --skip-generate | ||
|
|
||
| - name: Cache Next build | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: .next/cache | ||
| key: ${{ runner.os }}-next-${{ hashFiles('package-lock.json') }}-${{ github.sha }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-next-${{ hashFiles('package-lock.json') }}- | ||
|
|
||
| - name: Build | ||
| run: npm run build | ||
|
|
||
| - name: Cache Playwright browsers | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: ~/.cache/ms-playwright | ||
| key: ${{ runner.os }}-playwright-${{ hashFiles('package-lock.json') }} | ||
|
|
||
| - name: Install Playwright browsers | ||
| run: npx playwright install --with-deps chromium | ||
|
|
||
| - name: Run E2E tests | ||
| run: npx playwright test | ||
|
|
||
| - name: Dump MongoDB logs on failure | ||
| if: failure() | ||
| run: docker logs mongo || true | ||
|
|
||
| - name: Upload report on failure | ||
| if: failure() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: playwright-report | ||
| path: | | ||
| playwright-report/ | ||
| test-results/ | ||
| retention-days: 7 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -143,3 +143,8 @@ dist | |
|
|
||
| # Sentry Config File | ||
| .env.sentry-build-plugin | ||
|
|
||
| # Playwright | ||
| test-results/ | ||
| playwright-report/ | ||
| blob-report/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot why would you even do this in Opus 5 with MAX context when having fixed the replica set core issue already?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The
ensureUserAndProfilesplit only removes one implicit transaction, but other Prisma operations in the E2E suite (e.g. anycreatewith a nestedinclude,connectOrCreate, orupsert) still open implicit transactions and will hit P2031 against a standalone mongod. Running CI against a replica set is the correct long-term fix — it matches production topology and ensures any future Prisma write won't silently fail. TheensureUserAndProfilechange is a bonus that also helps local dev without a replica set.