Skip to content

Latest commit

 

History

History
99 lines (81 loc) · 8.93 KB

File metadata and controls

99 lines (81 loc) · 8.93 KB

Repository Guidelines

Project Structure & Module Organization

  • The Gradle build expects JVM sources in src/main/java and supporting Groovy/utility scripts in src/main/scripts and src/bin.
  • Application resources (icons, templates) should live under src/main/resources, while test fixtures sit in src/test/{java,groovy,resources,sql}.
  • Executable examples go in examples/, shared docs live in docs/, and generated artifacts stay in build/ (never commit them).
  • Launcher assets for packaged runtimes are kept in platform/ and install.sh shows how to assemble a platform-specific bundle.

Build, Test, and Development Commands

  • ./gradlew build -g ./.gradle-user compiles Java/Groovy sources, runs the full test suite, and produces jars in build/libs.
  • Use ./gradlew run -g ./.gradle-user for a fast developer launch that opens the JavaFX UI with your local classes.
  • ./gradlew runtimeZip -g ./.gradle-user creates the distributable runtime zips under build/. Run ./gradlew dependencyUpdates -Drevision=release -g ./.gradle-user before touching version.properties to see vetted upgrades.
  • If javafx is not supported in the environment, use targeted testing, ./gradlew test --tests "se.alipsa.gade.utils.*" -g ./.gradle-user runs only specified packages or classes.
  • Always run ./gradlew test -g ./.gradle-user when a task is finished to validate changes.
  • macOS Note: TestFX tests are automatically skipped on macOS due to known SIGTRAP crashes in Monocle. Tests pass successfully but JVM crashes during shutdown. Run ./gradlew test -DskipTestFx=false -g ./.gradle-user to force enable (tests will pass but build may report failure due to crash). Run ./gradlew test -DskipTestFx=true -g ./.gradle-user on any platform to skip TestFX tests.

Runtime Distribution & Launcher Scripts

  • The ./gradlew runtimeZip -g ./.gradle-user task creates platform-specific runtime packages under build/ that bundle the application, dependencies, and a JDK.
  • Each distribution contains launcher scripts that must be configured with the correct JVM arguments for Java 21 compatibility with the Gradle Tooling API.

Critical Scripts:

  • src/bin/cponly/gade.sh - Unix/Linux/macOS launcher script (manually maintained, copied to runtime distributions)
  • src/bin/cponly/gade.cmd - Windows launcher script (manually maintained, copied to runtime distributions)
  • build/image/gade-*/bin/gade - Auto-generated Unix scripts (created by beryx runtime plugin, configured via build.gradle)
  • build/image/gade-*/bin/gade.bat - Auto-generated Windows scripts (created by beryx runtime plugin, configured via build.gradle)

JVM Arguments for Java 21: The main Gade application (NOT the splash screen) requires these JVM args to allow Gradle Tooling API access to internal JDK modules:

--enable-native-access=javafx.graphics,javafx.media,javafx.web,ALL-UNNAMED
--add-opens=java.base/java.lang=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.io=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED

These are configured in:

  1. build.gradle - applicationDefaultJvmArgs for ./gradlew run and runtime plugin auto-generated scripts
  2. src/bin/cponly/gade.sh - Main application commands only (lines ~100-130, not splash screen)
  3. src/bin/cponly/gade.cmd - Main application command only (lines ~41-50, not splash screen)

Important: The splash screen commands only need --enable-native-access for JavaFX, not the --add-opens flags. Only the main Gade application needs full module access for the Gradle Tooling API. See docs/GRADLE_TOOLING_API_JAVA21.md for details.

Script Execution & Runtime Architecture

Gade executes Groovy scripts in a subprocess (RuntimeProcessRunner) that communicates with the main UI process via XML over TCP sockets (see ProtocolXml). The subprocess classpath is constructed by GroovyRuntimeManager.buildClassPathEntries().

Runtime types (RuntimeType enum): GADE, GRADLE, MAVEN, CUSTOM.

Key classes and their roles:

  • GroovyRuntimeManager (console/GroovyRuntimeManager.java) - Orchestrates runtime lifecycle: creates the classloader, builds the subprocess classpath, and starts the RuntimeProcessRunner. The resetClassloaderAndGroovy() method is the main entry point for runtime initialization.
  • RuntimeClassLoaderFactory (runtime/RuntimeClassLoaderFactory.java) - Creates a GroovyClassLoader per runtime type. All classloaders use ClassUtils.getBootstrapClassLoader() as parent for isolation from Gade application classes.
  • RuntimeProcessRunner (runtime/RuntimeProcessRunner.java) - Manages the long-lived subprocess: starts a JVM with the constructed classpath, connects via TCP socket, and provides async eval() for script execution.
  • GadeRunnerMain (runner/GadeRunnerMain.java) - Entry point for the subprocess JVM. Receives scripts over the socket and evaluates them in a GroovyShell.

Classpath construction (buildClassPathEntries):

  • GADE runtime: Only boot JAR on -cp. Groovy/Ivy + engine JAR loaded into ProcessRootLoader. Users add dependencies via @Grab.
  • Gradle runtime: Only boot JAR on -cp. Groovy/Ivy from deps + engine JAR loaded into ProcessRootLoader. Project dependencies resolved via Gradle Tooling API.
  • Maven runtime: Only boot JAR on -cp. Groovy/Ivy from deps + engine JAR loaded into ProcessRootLoader. Project dependencies resolved from pom.xml.
  • Custom runtime: Boot JAR + engine JAR + Groovy home jars + configured additional jars + classloader URLs on -cp.

Dependency resolution helpers:

  • GradleUtils / GradleDependencyResolver (utils/gradle/) - Resolves classpath via Gradle Tooling API.
  • MavenClasspathUtils (utils/maven/) - Resolves classpath from pom.xml via MavenUtils.
  • Upstream dependency policy: If a bug involves a dependency with groupId starting with se.alipsa, do not add a local workaround in Gade as the primary fix. Fix it in the related se.alipsa* project and report it there (preferably as a GitHub issue) before or alongside any temporary mitigation.

Distribution layout (after ./gradlew runtimeZip):

  • lib/groovy/ - Groovy and Ivy jars for the subprocess classpath.
  • lib/runtimes/ - gade-runner-boot.jar (JDK-only bootstrap, on subprocess -cp) and gade-runner-engine.jar (Groovy-dependent engine, loaded into ProcessRootLoader).
  • lib/app/ - Gade application jars (never included in subprocess classpath).

Coding Style & Naming Conventions

  • Java and Groovy code both follow two-space indents, braces on the same line, and descriptive camelCase identifiers (matrixLoader, semanticVersion).
  • Prefer final where fields should not mutate, and use Optional/null defensively around UI state.
  • Logging should go through Log4j2’s LogManager (private static final Logger log = ...).
  • Resource bundles, icons, and templates belong in src/main/resources with lowercase dashed filenames.

Testing Guidelines

  • UI-light logic belongs in src/test/java with naming ClassNameTest or behavior-oriented FeatureXTest.
  • Groovy scripts under test can mirror their runtime location inside src/test/groovy.
  • Use JUnit Jupiter APIs and keep tests deterministic—mock filesystem or Gradle calls where feasible.
  • When a bug is reported and no test currently fails for it, add a regression test that reproduces and guards against the issue whenever feasible.
  • Run ./gradlew test (or ./gradlew test --tests "se.alipsa.gade.utils.*" for a subset) before opening a PR and attach new fixtures to src/test/resources rather than embedding literals.

Commit & Pull Request Guidelines

  • Match the existing history: short, imperative commit subjects ("Ensure ivy runtime is available to isolated scripts"), optional context in the body, and reference issues with #id when applicable.
  • Each PR should describe purpose, highlight risky areas, enumerate manual/automated tests, and include UI screenshots or screen recordings when user-facing panes change.
  • Keep PRs focused; split refactors from feature changes, and check todo.md for related tasks before submitting.

Documentation Guidelines

  • Feature explanations, improvement summaries, and architectural decisions should be documented in docs/improvements/ unless otherwise instructed.
  • Use clear markdown formatting with sections for Problem, Solution, Testing, and Impact.
  • Include code examples where helpful, and link to related files with relative paths.
  • Keep the root directory clean—only essential files like README.md, CLAUDE.md, and AGENTS.md belong there.

Security & Configuration Tips

  • Never commit secrets or developer-specific tweaks; put overrides in env.sh/env.cmd alongside gade.sh and keep them untracked.
  • Use JAVA_OPTS to adjust memory or HiDPI scaling, and prefer JDK 21+ to match the toolchain enforced in build.gradle.
  • When configuring JDBC connections or REST endpoints for tests, point them at local containers or sanitized fixtures so the repo stays reproducible.