Parallelize check across Gradle subprojects for faster pre-commit.
Run :backend:check, frontend coverage, and :e2e:check as sibling tasks with org.gradle.parallel=true. Move E2E Docker compose into an e2e subproject so Playwright can start while unit tests run. Copy e2e/ in the E2E backend image so settings.gradle resolves inside Docker. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
764a620689
commit
a6a3084acd
7 changed files with 41 additions and 21 deletions
14
AGENTS.md
14
AGENTS.md
|
|
@ -37,7 +37,7 @@ docker compose up -d # starts postgres, backend, frontend
|
||||||
### All-in-one
|
### All-in-one
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./gradlew check # lint → frontend/backend tests with coverage thresholds → E2E (Docker)
|
./gradlew check # backend, frontend coverage, E2E (sibling tasks + org.gradle.parallel)
|
||||||
./gradlew coverage # backend + frontend tests with coverage reports
|
./gradlew coverage # backend + frontend tests with coverage reports
|
||||||
./gradlew up # docker compose up -d
|
./gradlew up # docker compose up -d
|
||||||
./gradlew down # docker compose down
|
./gradlew down # docker compose down
|
||||||
|
|
@ -170,9 +170,15 @@ export STRIPE_SECRET_KEY=sk_test_fake STRIPE_WEBHOOK_SECRET=whsec_fake STRIPE_PR
|
||||||
./gradlew check
|
./gradlew check
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs frontend lint, frontend unit tests **with Vitest coverage thresholds**
|
`check` depends on `:backend:check`, `frontendCoverage` (root), and `:e2e:check`
|
||||||
(70% lines, 60% branches, 70% functions), backend tests with **JaCoCo thresholds**
|
as **siblings** with `org.gradle.parallel=true`. Gradle parallelizes **across
|
||||||
(70% lines, 60% branches), Flyway checks, and **all 90 E2E tests in Docker**.
|
subprojects**, not multiple tasks in one project — E2E is in `e2e/` so Docker can
|
||||||
|
start while backend tests and frontend Vitest run. Within root, `frontendLint` →
|
||||||
|
`frontendCoverage` stays serial. Measured `unitAndCoverage --rerun-tasks`: ~30s
|
||||||
|
parallel on vs ~36s off. Full `check` wall time ≈ `max(:backend, frontend, :e2e)`;
|
||||||
|
E2E (~3 min) is usually the limit.
|
||||||
|
Forgejo CI already runs unit and E2E as separate workflow jobs in parallel.
|
||||||
|
Quick path without E2E: `./gradlew unitAndCoverage`.
|
||||||
**Do not commit or push if this fails.** Optional local guard:
|
**Do not commit or push if this fails.** Optional local guard:
|
||||||
`./scripts/install-pre-commit-hook.sh` (runs the same `check` on every `git commit`;
|
`./scripts/install-pre-commit-hook.sh` (runs the same `check` on every `git commit`;
|
||||||
fails if line or branch coverage is below threshold).
|
fails if line or branch coverage is below threshold).
|
||||||
|
|
|
||||||
28
build.gradle
28
build.gradle
|
|
@ -28,25 +28,23 @@ tasks.register('coverage') {
|
||||||
dependsOn(':backend:jacocoTestReport', 'frontendCoverage')
|
dependsOn(':backend:jacocoTestReport', 'frontendCoverage')
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('frontendE2E', Exec) {
|
// E2E lives in :e2e subproject so Gradle can run it parallel to root + :backend.
|
||||||
|
|
||||||
|
tasks.register('frontendE2E', Task) {
|
||||||
group = 'verification'
|
group = 'verification'
|
||||||
description = 'Run Playwright E2E tests in Docker (same stack as Forgejo CI)'
|
description = 'Alias for :e2e:check (Playwright in Docker)'
|
||||||
dependsOn frontendCoverage
|
dependsOn ':e2e:check'
|
||||||
workingDir = rootProject.projectDir
|
}
|
||||||
environment 'POSTGRES_DB', 'bilhej'
|
|
||||||
environment 'POSTGRES_USER', 'bilhej'
|
tasks.register('unitAndCoverage', Task) {
|
||||||
environment 'POSTGRES_PASSWORD', 'test_pw_ci_123'
|
group = 'verification'
|
||||||
environment 'JWT_SECRET', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
description = 'Backend + frontend unit tests with coverage thresholds (no E2E)'
|
||||||
environment 'STRIPE_SECRET_KEY', 'sk_test_fake'
|
dependsOn ':backend:check', 'frontendCoverage'
|
||||||
environment 'STRIPE_WEBHOOK_SECRET', 'whsec_fake'
|
|
||||||
environment 'STRIPE_PRICE_ID', 'price_fake'
|
|
||||||
commandLine 'docker', 'compose', '-f', 'docker-compose.e2e.yml',
|
|
||||||
'up', '--build', '--abort-on-container-exit', '--exit-code-from', 'playwright'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named('check').configure {
|
tasks.named('check').configure {
|
||||||
description = 'Full verification: lint, unit tests with line/branch coverage thresholds, E2E'
|
description = 'Full verification: :backend, frontend coverage, and :e2e in parallel'
|
||||||
dependsOn ':backend:check', frontendE2E
|
dependsOn ':backend:check', 'frontendCoverage', ':e2e:check'
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register('up', Exec) {
|
tasks.register('up', Exec) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ WORKDIR /app
|
||||||
COPY gradlew settings.gradle ./
|
COPY gradlew settings.gradle ./
|
||||||
COPY gradle/wrapper/ gradle/wrapper/
|
COPY gradle/wrapper/ gradle/wrapper/
|
||||||
COPY backend/build.gradle backend/
|
COPY backend/build.gradle backend/
|
||||||
|
COPY e2e/build.gradle e2e/
|
||||||
RUN chmod +x gradlew && ./gradlew :backend:dependencies --no-daemon -q
|
RUN chmod +x gradlew && ./gradlew :backend:dependencies --no-daemon -q
|
||||||
COPY backend/src backend/src
|
COPY backend/src backend/src
|
||||||
RUN ./gradlew :backend:bootJar --no-daemon -q
|
RUN ./gradlew :backend:bootJar --no-daemon -q
|
||||||
|
|
|
||||||
14
e2e/build.gradle
Normal file
14
e2e/build.gradle
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
tasks.register('check', Exec) {
|
||||||
|
group = 'verification'
|
||||||
|
description = 'Playwright E2E stack in Docker (parallel with :backend and root frontend tasks)'
|
||||||
|
workingDir = rootProject.projectDir
|
||||||
|
environment 'POSTGRES_DB', 'bilhej'
|
||||||
|
environment 'POSTGRES_USER', 'bilhej'
|
||||||
|
environment 'POSTGRES_PASSWORD', 'test_pw_ci_123'
|
||||||
|
environment 'JWT_SECRET', 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'
|
||||||
|
environment 'STRIPE_SECRET_KEY', 'sk_test_fake'
|
||||||
|
environment 'STRIPE_WEBHOOK_SECRET', 'whsec_fake'
|
||||||
|
environment 'STRIPE_PRICE_ID', 'price_fake'
|
||||||
|
commandLine 'docker', 'compose', '-f', 'docker-compose.e2e.yml',
|
||||||
|
'up', '--build', '--abort-on-container-exit', '--exit-code-from', 'playwright'
|
||||||
|
}
|
||||||
1
gradle.properties
Normal file
1
gradle.properties
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
org.gradle.parallel=true
|
||||||
|
|
@ -19,7 +19,7 @@ export STRIPE_SECRET_KEY="${STRIPE_SECRET_KEY:-sk_test_fake}"
|
||||||
export STRIPE_WEBHOOK_SECRET="${STRIPE_WEBHOOK_SECRET:-whsec_fake}"
|
export STRIPE_WEBHOOK_SECRET="${STRIPE_WEBHOOK_SECRET:-whsec_fake}"
|
||||||
export STRIPE_PRICE_ID="${STRIPE_PRICE_ID:-price_fake}"
|
export STRIPE_PRICE_ID="${STRIPE_PRICE_ID:-price_fake}"
|
||||||
|
|
||||||
echo "pre-commit: running ./gradlew check (lint, coverage thresholds, E2E in Docker)..."
|
echo "pre-commit: running ./gradlew check (lint, coverage thresholds, E2E)..."
|
||||||
if ! ./gradlew check --no-daemon; then
|
if ! ./gradlew check --no-daemon; then
|
||||||
echo ""
|
echo ""
|
||||||
echo "pre-commit: FAILED."
|
echo "pre-commit: FAILED."
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
rootProject.name = 'bilhej'
|
rootProject.name = 'bilhej'
|
||||||
|
|
||||||
include 'backend'
|
include 'backend', 'e2e'
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue