Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -367,9 +367,9 @@ Do **not** widen by reintroducing wildcards or a config-driven allow-list — th
- **Synchronizer artefact locations are registry-relative; `IRepository` paths are repository-absolute.** `SynchronizationWalker` strips the registry folder, so an artefact's `location` looks like `/myproject/file.ext` — but to read or write that file through `IRepository` you must prepend `IRepositoryStructure.PATH_REGISTRY_PUBLIC`. Code that confuses the two writes outside `/registry/public`, where no synchronizer, IT assertion, or Registry view will ever see the output (engine-intent shipped this bug once — see its CLAUDE.md "wrong turns"). The same convention shows up in `SynchronizationProcessor`'s cleanup pass and `CsvimProcessor.getCsvResource`.
- **`JsonHelper`/`GsonHelper` exclude fields without `@Expose` — and pretty-print.** Their Gson is built with `excludeFieldsWithoutExposeAnnotation()`, so `fromJson` into a POJO whose fields lack `@Expose` silently produces an all-null object (no exception — engine-intent's parser "worked" while generating nothing). Map-shaped data is unaffected (maps aren't field-reflected). For POJO mapping either annotate every field or use a private plain `Gson`; when asserting generated JSON content in tests remember the output is pretty-printed (`"key": "value"` with a space).
- **Stale H2 files break IT runs after a killed JVM.** The file-backed H2 under `tests/tests-integrations/target/dirigible` survives a killed test run and the next context fails to load with `missing artefact with name: [DefaultDB]` or `Table ... not found (this database is empty)` cascades. `rm -rf tests/tests-integrations/target/dirigible` before re-running locally.
- **Sample-project tests live in `tests/ui/tests/sample/`** — each extends `SampleProjectRepositoryIT` and overrides `getRepositoryURL()` + `verifyProject()`. `SampleProjectRepositoryIT` clones the repo through the IDE Git perspective, calls `Workbench.publishAll(true)`, and runs `forceProcessSynchronizers()` before delegating to `verifyProject()`. UI-based (Selenide → Chrome), slower than HTTP-only ITs. Inventory of sample repos under `dirigiblelabs/*`: `sample-entity-decorators`, `sample-java-entity-decorators`, `sample-roles-decorator`, `sample-job-decorator`, `sample-listener-decorator`, `sample-extension-decorator`, `sample-component-decorator`, `sample-websocket-decorator`, `sample-store-api`, `sample-intent-model`. When adding a new sample-project IT, drop the project in its own `dirigiblelabs/*` repo first, then reference the clone URL from the test. `IntentEditorLoadsIT` is not a `SampleProjectRepositoryIT` subclass (the intent generates in the workspace, not on publish) but uses the same clone-a-real-repo pattern: it clones `dirigiblelabs/sample-intent-model`, opens its `app.intent`, and drives the editor's Generate.
- **Sample-project tests live in `tests/ui/tests/sample/` and come in FAMILIES, not one class per sample.** `SampleProjectsIT` clones a *list* of `dirigiblelabs/*` repos through the IDE Git perspective, calls `Workbench.publishAll(true)` once, runs `forceProcessSynchronizers()` + `waitForStableSynchronization()`, and does all of that in a single `@BeforeAll` under `@TestInstance(PER_CLASS)` + `@DirtiesContext(AFTER_CLASS)`; each subclass then verifies one sample per `@Test`. UI-based (Selenide → Chrome), slower than HTTP-only ITs — which is exactly why the boot, the browser and the publish cycle are shared. Three subclasses: `TypeScriptSampleProjectsIT` (the TS/JS decorator samples), `JavaSampleProjectsIT` (the client-Java samples) and `SampleLibraryLocalNativeAppIT` (alone, because it spawns a real OS process). **The family split is a runtime constraint, not taste:** `sample-entity-decorators` and `sample-java-entity-decorators` both own the `SAMPLE_COUNTRY` table and both CSVIM-seed it, so they cannot be published into the same instance. Before adding a sample to a family, check it against the family for a table/route/queue/websocket-endpoint/Java-FQN collision (the whole family shares one `javac` batch and one `ClientClassLoader`), and keep the verification order-independent — the methods run against one live instance. When adding a new sample, drop the project in its own `dirigiblelabs/*` repo first, then add its URL to a family's `getRepositoryUrls()`. Inventory of sample repos under `dirigiblelabs/*`: `sample-entity-decorators`, `sample-java-entity-decorators`, `sample-roles-decorator`, `sample-job-decorator`, `sample-listener-decorator`, `sample-extension-decorator`, `sample-component-decorator`, `sample-websocket-decorator`, `sample-store-api`, `sample-intent-model`. `IntentEditorLoadsIT` is not a `SampleProjectsIT` subclass (the intent generates in the workspace, not on publish) but uses the same clone-a-real-repo pattern: it clones `dirigiblelabs/sample-intent-model`, opens its `app.intent`, and drives the editor's Generate.
- **Spring Boot 4 strips `ResponseStatusException.getReason()`** from the default JSON error body even with `server.error.include-message=always` in `application-common.properties`. Status code reaches the client correctly; the reason text doesn't. ITs asserting 404 must check `statusCode` only, not body content (`JavaEngineIT.delete_unregisters_handler` and `compile_error_keeps_endpoint_unregistered` learned this the hard way — see commit `f13c8c219e`).
- **The client-Java effort is split across three repositories.** The platform code (engine-java, data-store-java, IT) ships in this repo via PR [#5923](https://github.com/eclipse-dirigible/dirigible/pull/5923). The sample project that `JavaEntityDecoratorsSampleProjectIT` clones lives in [`dirigiblelabs/sample-java-entity-decorators`](https://github.com/dirigiblelabs/sample-java-entity-decorators) (initial content from PR [#1](https://github.com/dirigiblelabs/sample-java-entity-decorators/pull/1)). The announcement blog "Return of the Java – Decorators Awaken in Eclipse Dirigible" (sister piece to the December 2025 TS decorators post) goes through the docs portal in PR [`dirigible-io/dirigible-io.github.io#123`](https://github.com/dirigible-io/dirigible-io.github.io/pull/123). Follow-up Java-runtime features generally touch the same three places.
- **The client-Java effort is split across three repositories.** The platform code (engine-java, data-store-java, IT) ships in this repo via PR [#5923](https://github.com/eclipse-dirigible/dirigible/pull/5923). The sample project that `JavaSampleProjectsIT` clones lives in [`dirigiblelabs/sample-java-entity-decorators`](https://github.com/dirigiblelabs/sample-java-entity-decorators) (initial content from PR [#1](https://github.com/dirigiblelabs/sample-java-entity-decorators/pull/1)). The announcement blog "Return of the Java – Decorators Awaken in Eclipse Dirigible" (sister piece to the December 2025 TS decorators post) goes through the docs portal in PR [`dirigible-io/dirigible-io.github.io#123`](https://github.com/dirigible-io/dirigible-io.github.io/pull/123). Follow-up Java-runtime features generally touch the same three places.

## Browser UI — BlimpKit gotchas

Expand Down Expand Up @@ -459,7 +459,7 @@ The user-facing help portal at <https://www.dirigible.io/help/> documents the ID

The portal is **a separate repository** — MkDocs-built from <https://github.com/dirigible-io/dirigible-io.github.io> (Markdown sources under `docs-help/docs/`, nav in `docs-help/mkdocs.yml`). Doc fixes go there as PRs, not in this repo. Blog posts (`docs-blogs/docs/YYYY/MM/DD/*.md`) need three coordinated updates per post: the markdown source, `docs/blogs.json` (CI normally regenerates from the last 5 dated `.md` files via `.github/folders.sh`, but a manual edit lights the home page up immediately), and `docs-blogs/mkdocs.yml` nav (year heading + per-post entry). The `docs/` tree is otherwise CI-generated — see the repo's own `CLAUDE.md` and don't hand-edit it for routine changes; `ci skip` in a commit message *suppresses* the regeneration job.

The companion sample repos under `dirigiblelabs/*` are also separate. For end-to-end tests that clone such repos (`SampleProjectRepositoryIT` subclasses), the merge order follows the dependency direction, both ways: a dirigible-side IT that expects new sample content needs the sample-side PR merged first (else it clones an empty `master`), and a sample-side change that uses new platform APIs needs the platform PR merged first — the ITs clone the sample repo's HEAD, so merging the sample early breaks **every** PR's CI and master until the platform lands (this happened with the typed-handler interfaces: sample PR merged a day before platform PR [#6010](https://github.com/eclipse-dirigible/dirigible/pull/6010), and `JavaEntityDecoratorsSampleProjectIT` failed across the board until #6010 merged). Re-running a failed PR check does NOT pick up a newer master — re-runs build the original merge snapshot; use `gh pr update-branch` (or push) to get a fresh merge.
The companion sample repos under `dirigiblelabs/*` are also separate. For end-to-end tests that clone such repos (`SampleProjectsIT` subclasses), the merge order follows the dependency direction, both ways: a dirigible-side IT that expects new sample content needs the sample-side PR merged first (else it clones an empty `master`), and a sample-side change that uses new platform APIs needs the platform PR merged first — the ITs clone the sample repo's HEAD, so merging the sample early breaks **every** PR's CI and master until the platform lands (this happened with the typed-handler interfaces: sample PR merged a day before platform PR [#6010](https://github.com/eclipse-dirigible/dirigible/pull/6010), and the Java entity-decorators verification failed across the board until #6010 merged). Re-running a failed PR check does NOT pick up a newer master — re-runs build the original merge snapshot; use `gh pr update-branch` (or push) to get a fresh merge.

Treat `modules/commons/commons-config/src/main/java/org/eclipse/dirigible/commons/config/DirigibleConfig.java` (the enum) and `Configuration.java` (the allow-list) as the source of truth for env-var names and defaults, not the portal — the env-vars page lags the code by months. Specifically, the in-repo OAuth flow is Spring's `spring.security.oauth2.client.registration.github.*` activated by the `github` profile and configured via `DIRIGIBLE_GITHUB_CLIENT_ID` / `_CLIENT_SECRET` / `_SCOPE` (`build/application/src/main/resources/application-github.properties`), not the generic `DIRIGIBLE_OAUTH_*` entries some doc pages still describe. Current servlet mappings are rooted at `/services/...` and `/public/...` per `BaseEndpoint`; any `/services/v4/...` URL in a doc snippet is legacy.

Expand All @@ -480,9 +480,9 @@ The full Selenide UI suite takes ~1.5h per DB, so it does **not** run on every P
- **`nightly.yml`** (cron `0 2 * * *` + `workflow_dispatch`) and **push to master** (`build.yml`) run the **full** suite on H2 + PostgreSQL.

**Test tagging convention (JUnit 5 `@Tag`, wired to failsafe via the `${it.groups}` / `${it.excludedGroups}` properties in the root `pom.xml`):**
- Every browser-driven IT is `@Tag("ui")` - inherited from the `UserInterfaceIntegrationTest` base (and thus by `SampleProjectRepositoryIT` and all sample-project ITs). Do not tag these individually.
- Every browser-driven IT is `@Tag("ui")` - inherited from the `UserInterfaceIntegrationTest` base (and thus by `SampleProjectsIT` and all sample-project ITs). Do not tag these individually.
- HTTP-level ITs (`extends IntegrationTest` directly) carry no tag, so they are always in the smoke set.
- To force a specific UI IT to run on every PR, add `@Tag("smoke")` to that class (keep the list small - smoke must stay fast).
- Shard-routing tags: `@Tag("sample")` sits on the `SampleProjectRepositoryIT` base (inherited by every sample-project IT); `@Tag("camel")` sits on each IT in `ui/tests/camel` (their `PredefinedProjectIT` base is shared with non-camel tests, so the base cannot carry it — tag new camel ITs individually). These route classes into the `samples` CI shard; everything else UI stays in the `ui` shard.
- Shard-routing tags: `@Tag("sample")` sits on the `SampleProjectsIT` base (inherited by every sample-project IT); `@Tag("camel")` sits on each IT in `ui/tests/camel` (their `PredefinedProjectIT` base is shared with non-camel tests, so the base cannot carry it — tag new camel ITs individually). These route classes into the `samples` CI shard; everything else UI stays in the `ui` shard.

`codeql.yml`, `release.yml` cover CodeQL and Maven Central release respectively.
2 changes: 1 addition & 1 deletion CLAUDE_FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ native-image -jar build/application/target/dirigible-application-*-executable.ja
### 10.6 Tests
- `tests/tests-framework/` — Selenide / Spring test base classes.
- `tests/tests-integrations/` — `*IT.java` Selenide-driven UI integration tests with per-test fixture projects under `src/main/resources/<TestName>/`.
- `tests/ui/tests/sample/` — `SampleProjectRepositoryIT` subclasses that clone `dirigiblelabs/sample-*` repos, publish them, and call `verifyProject()`.
- `tests/ui/tests/sample/` — `SampleProjectsIT` subclasses that clone a family of `dirigiblelabs/sample-*` repos into one workspace, publish them together, and verify one sample per `@Test`.
- HTTP-only ITs (faster, headless) extend `IntegrationTest` and call `SynchronizationProcessor.forceProcessSynchronizers()` directly — see `JavaEngineIT`.
- Surefire (`*Test.java`) = unit. Failsafe (`*IT.java`) = integration. Naming matters.
- `-D selenide.headless=true` is the headless flag.
Expand Down
2 changes: 1 addition & 1 deletion components/engine/engine-intent/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ heading, because VitePress collapses an em dash to ONE hyphen (`#stage-what-a-st
GitHub's markdown keeps TWO (`#stage--what-a-status-means…`), so the same heading needs a different
link in each repo.

`IntentEditorLoadsIT` **clones [`dirigiblelabs/sample-intent-model`](https://github.com/dirigiblelabs/sample-intent-model)** (the library intent sample - same clone-a-real-repo pattern as the `SampleProjectRepositoryIT` subclasses; it replaced the old local `IntentEditorIT` fixture so the published sample stays the single source of truth), opens its `app.intent`, then asserts the mxGraph diagram renders (`.intent-diagram svg` is visible) **and** that the parsed `Book` entity's label appears inside `.intent-diagram` - so it fails on an empty or broken diagram, unlike the old "any `<svg>` exists" check that a Mermaid error bomb satisfied. It does not separately exercise a theme switch because the fixed-colour palette renders identically in both themes. Editing the sample's entities/process means the sample repo must change too (the IT clones its HEAD). `IntentEngineIT` stays self-contained (inline YAML) for fast, network-free coverage.
`IntentEditorLoadsIT` **clones [`dirigiblelabs/sample-intent-model`](https://github.com/dirigiblelabs/sample-intent-model)** (the library intent sample - same clone-a-real-repo pattern as the `SampleProjectsIT` subclasses; it replaced the old local `IntentEditorIT` fixture so the published sample stays the single source of truth), opens its `app.intent`, then asserts the mxGraph diagram renders (`.intent-diagram svg` is visible) **and** that the parsed `Book` entity's label appears inside `.intent-diagram` - so it fails on an empty or broken diagram, unlike the old "any `<svg>` exists" check that a Mermaid error bomb satisfied. It does not separately exercise a theme switch because the fixed-colour palette renders identically in both themes. Editing the sample's entities/process means the sample repo must change too (the IT clones its HEAD). `IntentEngineIT` stays self-contained (inline YAML) for fast, network-free coverage.

### General build/serve gotcha (applies to all UI modules)

Expand Down
8 changes: 4 additions & 4 deletions components/engine/engine-java/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,9 +189,9 @@ browser-IDE developer sees what's wrong without reading the server log.

- Platform: this repo, PR #6051.
- Samples: `dirigiblelabs/sample-java-{entity,listener,job,websocket,extension}-decorator` — each shows the
styles above; the entity sample is the kitchen-sink. The `Java*DecoratorsSampleProjectIT` /
`Java*DecoratorSampleProjectIT` clone these repos' HEAD, so **merge order is load-bearing**: the
platform PR merges first; the sample-clone ITs are temporarily `@Disabled` until the sample PRs land
(the samples' old API doesn't compile against the new engine). Re-enable them after.
styles above; the entity sample is the kitchen-sink. `JavaSampleProjectsIT` clones all five repos'
HEAD into one workspace and publishes them together, so **merge order is load-bearing**: the
platform PR merges first; that IT is temporarily `@Disabled` until the sample PRs land (the samples'
old API doesn't compile against the new engine). Re-enable it after.
- Docs: `dirigible-io/dirigible-io.github.io` — `/help/develop` (incl. a "Coming from Spring Boot"
guide) and `/sdk`.
2 changes: 1 addition & 1 deletion components/engine/engine-native-apps/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ User projects can declare a `*.nativeapp` JSON file that turns an external web s
- **Gotchas worth remembering.**
- `Python 3.14` on macOS has a bind regression in `http.server.HTTPServer` — don't use Python for embedded test servers; use `java Server.java`.
- `ServerSocket(port, 0, InetAddress.getLoopbackAddress())` can succeed on loopback even when another listener is bound to `0.0.0.0:port` on macOS — this is why `PortResolver.isBindable` deliberately probes the wildcard interface (`new ServerSocket(port, 0, null)`). Keep it that way; reverting to a loopback probe will reintroduce silent `EADDRINUSE` failures when the parent platform (or any other process) is already on the preferred port.
- `Spring Boot's DevTools` (or whatever `FileSystemWatcher` wires up) can deadlock against `sun.nio.fs.PollingWatchService$PollingWatchKey` on macOS during full IT runs (last seen on `JavaLspIT`, `CreateNewFileIT`, `JavaEntityDecoratorsSampleProjectIT`). This is NOT a native-apps regression. When the full reactor IT run hangs, jstack the surefire JVM and check for `Found one Java-level deadlock` between `main` and `FileSystemWatcher`.
- `Spring Boot's DevTools` (or whatever `FileSystemWatcher` wires up) can deadlock against `sun.nio.fs.PollingWatchService$PollingWatchKey` on macOS during full IT runs (last seen on `JavaLspIT`, `CreateNewFileIT`, `JavaSampleProjectsIT`). This is NOT a native-apps regression. When the full reactor IT run hangs, jstack the surefire JVM and check for `Found one Java-level deadlock` between `main` and `FileSystemWatcher`.
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public static void waitForSynchronizationExecution() {
* Wait until the synchronizer stays idle for a full quiet period. A plain idle check is not enough
* right after a publish: the registry file watcher (a polling watcher on some platforms) delivers
* trailing change events SECONDS after the copy, scheduling one more cycle - which may re-register
* data-store entities and rebuild their tables mid-test (StoreAPISampleProjectIT saw its
* data-store entities and rebuild their tables mid-test (the store-api sample verification saw its
* just-inserted rows vanish exactly this way). Requiring the idle condition to HOLD for ten seconds
* absorbs those late events before the test proceeds.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
* (a missing {@code ng-editor} platform-links category, or the config script not being loaded, both
* leave the services green while the editor is dead). This test clones the
* {@code dirigiblelabs/sample-intent-model} sample project (the same clone-a-real-repo pattern the
* {@code SampleProjectRepositoryIT} subclasses use), opens its {@code app.intent}, and asserts:
* {@code SampleProjectsIT} subclasses use), opens its {@code app.intent}, and asserts:
* <ul>
* <li>the file is routed to the Intent Editor (the editor tab appears),</li>
* <li>the AngularJS {@code intentEditor} module actually bootstrapped (its injector resolves -
Expand Down
Loading
Loading