Skip to content

chore(ci): cover ee-less backend build and frontend unit tests#3824

Open
Anty0 wants to merge 7 commits into
mainfrom
jirikuchynka/ci-ee-less-coverage
Open

chore(ci): cover ee-less backend build and frontend unit tests#3824
Anty0 wants to merge 7 commits into
mainfrom
jirikuchynka/ci-ee-less-coverage

Conversation

@Anty0

@Anty0 Anty0 commented Jul 24, 2026

Copy link
Copy Markdown
Member

Problem

CI covered building/testing the platform without the enterprise (ee) modules only partially:

with ee without ee (before)
Backend build (compile main) ❌ never compiled ee-less — runWithoutEeTests reuses the with-ee jar (SKIP_SERVER_BUILD=true)
Frontend build + tsc ✅ (frontend-code-check removes src/ee)
Frontend unit tests frontend-test always ran with ee present

So a change that broke the OSS build's compilation of the main backend could pass CI.

Change

Two new jobs in test.yml, both wired into the everything-passed gate:

  • backend-build-without-eerm -rf ./ee, then a real ./gradlew classes jar bootJar without SKIP_SERVER_BUILD, verifying the main backend compiles and packages with the enterprise modules absent.
  • frontend-test-without-eerm -rf ./src/ee before npm ci so the prepare hook (prepareEe.js) links the OSS stub (eeModule.currenteeModule.oss), then runs the webapp unit suite.

Scope of frontend-test-without-ee

This job runs the webapp unit suite with src/ee removed, so any unit test that reaches ee code through the tg.ee alias is exercised against the OSS stub instead of the real ee module. No unit test does so today, so the job currently carries no unique signal — it is a forward-looking guard for future ee-consuming unit tests. OSS type/build resolution is already covered separately by frontend-code-check's "Check it builds without ee directory" step. Kept as a deliberate tradeoff (small CI cost now for automatic OSS coverage of future ee-consuming unit tests).

Defect this surfaced (also fixed here)

The new backend-build-without-ee job immediately caught a pre-existing latent bug: the OSS backend did not compile without ee.

BranchMergeE2eDataController (added in the branching feature, #3246) lives in the :development module, which is unconditionally on server-app's classpath. But it imported the ee-only BranchSnapshotService directly, while :development depends on :ee-app only when the ee directory exists. With ee removed, the module failed to compile.

Fix: move the controller into a new ee-only source root (src/mainEe/kotlin) added to the :development source set only when eeAppDirectoryExists, mirroring the existing conditional :ee-app dependency. Package is unchanged, so component scanning still registers it when ee is present.

Summary by CodeRabbit

  • Tests
    • Added CI jobs to validate backend build and frontend unit tests succeed when enterprise components are absent.
    • Updated CI dependency and failure aggregation to include the new “without enterprise” checks.
    • Added enterprise e2e data support for branch-merge scenarios, including initial branch snapshot creation.
  • Bug Fixes
    • Improved build configuration to include enterprise-specific source directories only when they exist.

Add two CI jobs to close gaps in without-ee coverage:

- backend-build-without-ee: removes ./ee and runs a full compile+package
  (classes jar bootJar) without SKIP_SERVER_BUILD, so the main backend is
  actually built without the enterprise modules. The existing
  runWithoutEeTests reuses the with-ee jar and never verifies compilation.
- frontend-test-without-ee: removes webapp/src/ee before npm ci (so the
  prepare hook points the tg.ee symlink at the OSS stub) and runs the
  webapp unit tests. Unit tests previously always ran with ee present.

Both jobs are wired into the everything-passed gate.
@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79d78c50-57ba-45a0-a3a9-113015572832

📥 Commits

Reviewing files that changed from the base of the PR and between 63ac4f2 and a8e316c.

📒 Files selected for processing (1)
  • .github/workflows/test.yml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/test.yml

📝 Walkthrough

Walkthrough

The workflow adds backend and frontend verification without EE code and includes both jobs in final status aggregation. The backend build conditionally includes EE Kotlin sources, and a new internal controller prepares branch-merge E2E data and creates an initial snapshot.

Changes

Enterprise-excluded CI verification

Layer / File(s) Summary
Add enterprise-excluded verification jobs
.github/workflows/test.yml
Backend artifacts are built and frontend unit tests run after removing the corresponding EE directories.
Aggregate verification results
.github/workflows/test.yml
everything-passed waits for the new jobs and records either job as failed when its result is not successful.

Branch merge E2E data setup

Layer / File(s) Summary
Create branch merge E2E data and snapshot
backend/development/build.gradle, backend/development/src/mainEe/kotlin/.../BranchMergeE2eDataController.kt
The build conditionally includes EE Kotlin sources. The new controller creates branch-merge test data and invokes initial branch snapshot creation after storage.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant E2EDataClient
  participant BranchMergeE2eDataController
  participant BranchSnapshotService
  E2EDataClient->>BranchMergeE2eDataController: submit branch-merge test data
  BranchMergeE2eDataController->>BranchSnapshotService: createInitialSnapshot(project.id, mainBranch, featureBranch)
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main CI change: adding ee-less backend build and frontend unit test coverage.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch jirikuchynka/ci-ee-less-coverage

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/test.yml:
- Around line 32-36: Restrict GitHub token access for both build jobs in the
workflow by adding job-level permissions with contents read only, and update
each actions/checkout step to set persist-credentials to false. Grant no
additional scopes unless an existing step explicitly requires them.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5058ee03-da04-468d-8957-98de74817532

📥 Commits

Reviewing files that changed from the base of the PR and between 7c9823d and 0b2a8ee.

📒 Files selected for processing (1)
  • .github/workflows/test.yml

Comment thread .github/workflows/test.yml
BranchMergeE2eDataController lives in the :development module, which is
unconditionally on server-app's classpath, but it imported the ee-only
BranchSnapshotService directly. :development depends on :ee-app only when
the ee directory exists, so the OSS build (no ee) failed to compile it.

Move the controller into a new ee-only source root
(src/mainEe/kotlin) that is added to the :development source set only when
eeAppDirectoryExists, mirroring the existing conditional :ee-app dependency.
Package is unchanged, so component scanning still registers it when ee is
present.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt`:
- Around line 15-24: Make currentTestData in BranchMergeE2eDataController
request-local so concurrent requests cannot overwrite the test data used by
afterTestDataStored. Prefer request scope for the controller or propagate the
BranchMergeTestData instance through the callback, ensuring afterTestDataStored
reads the matching request’s data rather than singleton-shared state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 41becb28-9e4d-4178-b2d1-4c21d00683d2

📥 Commits

Reviewing files that changed from the base of the PR and between 0b2a8ee and 0f7d702.

📒 Files selected for processing (2)
  • backend/development/build.gradle
  • backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt`:
- Around line 15-24: Make currentTestData in BranchMergeE2eDataController
request-local so concurrent requests cannot overwrite the test data used by
afterTestDataStored. Prefer request scope for the controller or propagate the
BranchMergeTestData instance through the callback, ensuring afterTestDataStored
reads the matching request’s data rather than singleton-shared state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 41becb28-9e4d-4178-b2d1-4c21d00683d2

📥 Commits

Reviewing files that changed from the base of the PR and between 0b2a8ee and 0f7d702.

📒 Files selected for processing (2)
  • backend/development/build.gradle
  • backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt
🛑 Comments failed to post (1)
backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt (1)

15-24: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -A10 -B4 'annotation class InternalController|`@RequestScope`|`@Scope`' backend --glob '*.kt'

Repository: tolgee/tolgee-platform

Length of output: 40910


🏁 Script executed:

#!/bin/bash
set -euo pipefail

files=(
  backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt
  backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/AbstractE2eDataController.kt
  backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PermissionsE2eDataController.kt
)

for f in "${files[@]}"; do
  echo "===== $f ====="
  wc -l "$f"
  echo "--- outline ---"
  ast-grep outline "$f" --view expanded || true
  echo
done

echo "===== targeted excerpts ====="
sed -n '1,220p' backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt
echo "-----"
sed -n '1,240p' backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/AbstractE2eDataController.kt
echo "-----"
sed -n '1,120p' backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PermissionsE2eDataController.kt

Repository: tolgee/tolgee-platform

Length of output: 417


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate files =="
fd -a 'BranchMergeE2eDataController.kt|AbstractE2eDataController.kt|PermissionsE2eDataController.kt|InternalController.kt' backend

echo "== inspect outlines =="
for f in $(fd -a 'BranchMergeE2eDataController.kt|AbstractE2eDataController.kt|PermissionsE2eDataController.kt|InternalController.kt' backend); do
  echo "===== $f ====="
  wc -l "$f"
  ast-grep outline "$f" --view expanded || true
  echo
done

echo "== targeted excerpts =="
for f in $(fd -a 'BranchMergeE2eDataController.kt|AbstractE2eDataController.kt|PermissionsE2eDataController.kt|InternalController.kt' backend); do
  echo "----- $f -----"
  sed -n '1,240p' "$f"
  echo
done

Repository: tolgee/tolgee-platform

Length of output: 11910


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' backend/data/src/main/kotlin/io/tolgee/data/service/TestDataGeneratingService.kt
echo "-----"
sed -n '1,220p' backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt
echo "-----"
rg -n "afterTestDataStored\\(|createInitialSnapshot\\(|currentTestData" backend/development/src/main/kotlin backend/data/src/main/kotlin --glob '*.kt'

Repository: tolgee/tolgee-platform

Length of output: 284


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' backend/data/src/main/kotlin/io/tolgee/data/service/TestDataGeneratingService.kt
echo "-----"
sed -n '1,220p' backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt
echo "-----"
rg -n "afterTestDataStored\\(|createInitialSnapshot\\(|currentTestData" backend/development/src/main backend/data/src/main --glob '*.kt'

Repository: tolgee/tolgee-platform

Length of output: 284


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate generation service =="
fd -a 'TestDataGeneratingService.kt|BranchMergeE2eDataController.kt|AbstractE2eDataController.kt' backend

echo "== read generation service =="
for f in $(fd -a 'TestDataGeneratingService.kt|BranchMergeE2eDataController.kt|AbstractE2eDataController.kt' backend); do
  echo "===== $f ====="
  wc -l "$f"
  sed -n '1,260p' "$f"
  echo
done

echo "== find lifecycle uses =="
rg -n "generate\\(|afterTestDataStored\\(|saveTestData\\(" backend --glob '*.kt'

Repository: tolgee/tolgee-platform

Length of output: 50378


Make currentTestData request-local.

BranchMergeE2eDataController is singleton-scoped, so this shared mutable field can be overwritten by another request before afterTestDataStored runs. Use request scope or pass the BranchMergeTestData instance through the callback instead of reading shared state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/development/src/mainEe/kotlin/io/tolgee/controllers/internal/e2eData/BranchMergeE2eDataController.kt`
around lines 15 - 24, Make currentTestData in BranchMergeE2eDataController
request-local so concurrent requests cannot overwrite the test data used by
afterTestDataStored. Prefer request scope for the controller or propagate the
BranchMergeTestData instance through the callback, ensuring afterTestDataStored
reads the matching request’s data rather than singleton-shared state.

Anty0 added 2 commits July 24, 2026 17:39
frontend-test-without-ee deletes the only ee-importing tests and the
remaining webapp unit tests never touch tg.ee, so the OSS stub module
(eeModule.oss) had no assertions: it could regress silently and the job
would stay green. Add eeModule.oss.test.ts asserting the stub's
load-bearing OSS behaviour (QA reported disabled, no billing/apps/task/
glossary contributions, menu adders leave items untouched). It imports
eeModule.oss directly (like eeCheck.ts) so the stub is validated in both
the with-ee and without-ee unit-test runs.

Also correct the test.yml comment: tg.ee is a TypeScript path alias; the
symlink prepareEe.js repoints is eeModule.current.
eeModule.oss.test.ts only restated the stub's own literals (() => false
asserted toBe(false), literal [] asserted empty), so it could not catch a
regression that matters, and it imported eeModule.oss directly, bypassing
the tg.ee symlink production uses, so it gave frontend-test-without-ee no
signal the ordinary frontend-test job lacks.

Keep frontend-test-without-ee as a forward-looking guard: any future unit
test that consumes ee through tg.ee is exercised against the OSS stub when
src/ee is removed. Document that scope on the job; OSS type/build
resolution is already covered by frontend-code-check's builds-without-ee
step.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/test.yml (1)

630-633: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve the existing frontend-test check in the final gate.

This change appears to replace the normal frontend test result with frontend-test-without-ee. Check both results; otherwise ordinary frontend test failures could be ignored when the enterprise-less job succeeds.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/test.yml around lines 630 - 633, Update the final gate to
check both needs.frontend-test.result and needs.frontend-test-without-ee.result,
adding each corresponding job to failed_jobs when its result is not success.
Preserve the existing frontend-test failure detection while retaining the
enterprise-less check.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/test.yml:
- Around line 630-633: Update the final gate to check both
needs.frontend-test.result and needs.frontend-test-without-ee.result, adding
each corresponding job to failed_jobs when its result is not success. Preserve
the existing frontend-test failure detection while retaining the enterprise-less
check.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 38a6ac3e-49af-4697-aa22-230933a2c482

📥 Commits

Reviewing files that changed from the base of the PR and between 68f9a4f and b09025a.

📒 Files selected for processing (1)
  • .github/workflows/test.yml

Anty0 added 3 commits July 25, 2026 04:34
The five-line comment restated the job name, carried PR-description
rationale, and cross-referenced another job's step (which would rot if
that step is renamed). The load-bearing ordering fact stays in the
two-line comment at the Remove ee step.
- Drop the rot-prone symlink-internals parenthetical from the Remove ee
  comment; the pointer to prepareEe.js plus the ordering consequence stand
  on their own.
- Pair src/mainEe/kotlin with src/mainEe/java in the :development source
  set, matching the kotlin+java pairing every sibling module uses (no-op
  today, but a future ee-only .java would otherwise be silently excluded).
Add job-level 'permissions: contents: read' and 'persist-credentials:
false' to backend-build-without-ee and frontend-test-without-ee. Both
only check out and build/test (no artifact upload, push, or check
posting), so read-only access is sufficient. Cannot be set workflow-wide
because the test-reporter jobs need checks: write.
@Anty0
Anty0 requested a review from dkrizan July 26, 2026 13:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant