-
Notifications
You must be signed in to change notification settings - Fork 1
build(native-image): add cross-platform GraalVM native-image workflow #57
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
Conversation
- Add GitHub Actions workflow `build-native-image.yml` for GraalVM native-image binary builds on macOS and Ubuntu - Update `.gitignore` for native-image build artifacts and outputs - Provide instructions for building and testing native images in documentation (see README and copilot-instructions) - Enable CI artifact upload for platform-specific native binaries Motivation: Enables efficient cross-platform deployments and easier distribution of ChronDB as a native binary, improving startup time and resource usage, especially for cloud and container environments. Related: - Docs: AGENT.md, README.md, .github/copilot-instructions.md - Native image support: `dev/chrondb/native_image.clj`, build script, updated ignore rules fixed: #12 Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughWalkthroughAdds GraalVM native-image support and related tooling: CI workflow, Dockerfile, build scripts and native-image config generator; updates deps, gitignore, docs (AGENT.md, operations), changelog, and minor type hints/AOT and JGit type annotations across source files. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer / CI
participant Build as chrondb.build
participant NI as chrondb.native-image
participant GI as GraalVM_native-image
participant Store as Artifact Upload
Dev->>Build: invoke -m chrondb.build [--uberjar]
Build->>Build: clean, write POM, copy & compile sources
Build->>Build: package jar / uberjar
Build->>NI: prepare-files (generate native-image args & configs)
NI-->>Build: return args & config paths
Build->>GI: native-image @native-image-args (OS-specific)
GI-->>Build: produce binary (chrondb_<os>)
Build->>Store: upload artifact / Docker registry
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
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.
Pull Request Overview
This PR adds comprehensive GraalVM native-image build support to ChronDB, enabling cross-platform native binary distribution for improved startup performance and resource usage.
Key changes:
- Added GitHub Actions workflow for automated cross-platform native binary builds on macOS and Ubuntu
- Implemented native-image configuration and build tooling with proper reflection and resource settings
- Added type hints throughout the codebase to optimize GraalVM compilation
Reviewed Changes
Copilot reviewed 12 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/build-native-image.yml |
GitHub Actions workflow for building native binaries on macOS/Ubuntu |
dev/chrondb/native_image.clj |
Native-image configuration generator with GraalVM-specific settings |
dev/chrondb/build.clj |
Build script for JAR creation and native-image preparation |
src/chrondb/core.clj |
Added :gen-class for native-image main class support |
src/chrondb/storage/git/commit.clj |
Added type hints for JGit classes to improve native compilation |
src/chrondb/api/sql/connection/server.clj |
Added type hint for ServerSocket |
src/chrondb/api/redis/core.clj |
Added type hints for ServerSocket instances |
docs/operations.md |
Documentation for building and using native images |
AGENT.md |
Comprehensive project guidelines moved from .github/copilot-instructions.md |
CHANGELOG.md |
Updated to reflect native binary support addition |
.github/copilot-instructions.md |
Replaced with reference to AGENT.md |
.cursorrules |
Added reference to AGENT.md |
Comments suppressed due to low confidence (1)
dev/chrondb/native_image.clj:1
- Environment variable name should be 'CHRONDB_VERSION' instead of 'CHROND_VERSION' to match the project name.
(ns chrondb.native-image
dev/chrondb/native_image.clj
Outdated
| (doseq [[fname contents] [["reflect-config.json" "[]"] | ||
| ["resource-config.json" (json/write-str {:resources {:includes []}})]]] | ||
| (let [file (io/file native-config-dir fname)] | ||
| (when-not (.exists file) | ||
| (spit file contents)))))) |
Copilot
AI
Oct 10, 2025
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.
This fallback configuration creation is redundant since the same files are already created with proper content earlier in the function (lines 220-221). The fallback logic should be removed to avoid confusion.
| (doseq [[fname contents] [["reflect-config.json" "[]"] | |
| ["resource-config.json" (json/write-str {:resources {:includes []}})]]] | |
| (let [file (io/file native-config-dir fname)] | |
| (when-not (.exists file) | |
| (spit file contents)))))) | |
| ))) |
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.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/chrondb/storage/git/commit.clj (1)
70-81: Return a real Ref for bare repos; avoid reified stub.Reifying Ref with only getName risks downstream breakage. Create/update the ref and return the actual repository ref.
- (if ref - (reify org.eclipse.jgit.lib.Ref - (getName [_] branch-name)) - ;; If the branch doesn't exist, create it - (let [ref-update (.updateRef repository (str "refs/heads/" branch-name)) - head-id (.resolve repository Constants/HEAD)] - (.setNewObjectId ref-update (or head-id (ObjectId/zeroId))) - (.update ref-update) - (reify org.eclipse.jgit.lib.Ref - (getName [_] branch-name))))) + (if ref + ref + (let [ref-name (str "refs/heads/" branch-name) + ref-update (.updateRef repository ref-name) + head-id (.resolve repository Constants/HEAD)] + (.setNewObjectId ref-update (or head-id (ObjectId/zeroId))) + (.update ref-update) + (.exactRef repository ref-name))))deps.edn (1)
10-12: Align Lucene versions & enable uberjar in:buildalias.
- Bump
lucene-analyzers-commonto 9.8.0 (match other modules).- Add
"--uberjar"to:buildalias:main-optssochrondb.buildproduces an uberjar for native-image.Apply these diffs:
--- deps.edn @@ -10,7 +10,7 @@ org.apache.lucene/lucene-core {:mvn/version "9.8.0"} org.apache.lucene/lucene-queryparser {:mvn/version "9.8.0"} - org.apache.lucene/lucene-analyzers-common {:mvn/version "8.11.2"} + org.apache.lucene/lucene-analyzers-common {:mvn/version "9.8.0"} @@ -82,7 +82,8 @@ :build {:deps {io.github.clojure/tools.build {:git/tag "v0.9.4" :git/sha "76b78fe"}} - :extra-paths ["dev"] - :main-opts ["-m" "chrondb.build"]} + :extra-paths ["dev"] + :main-opts ["-m" "chrondb.build" "--uberjar"]}
🧹 Nitpick comments (5)
.github/workflows/build-native-image.yml (1)
24-30: Upgrade GraalVM to v25
The workflow currently pins GraalVM 22.3.2 (Sept 2022). As of Oct 2025, GraalVM 25 (Sept 16 2025) is available with key native-image improvements:
- WP-SCCP enabled by default for smaller, more accurate images
- Refined O2/O3 control-split profile models
- Default SBOM embedding and experimental symbol obfuscation
- New
-H:Preserveoption and enhanced Vector API support
Evaluate upgrading to v25 in.github/workflows/build-native-image.ymland test compatibility. If you must stay on 22.3.2, please document the rationale.AGENT.md (1)
96-101: Doc: include --uberjar for native-image build flow.Without an uberjar, native-image will miss dependencies and likely fail. Update the command.
- - Use `clojure -M:build` to gerar o artefato `target/chrondb.jar` e preparar arquivos auxiliares para o GraalVM + - Use `clojure -M:build --uberjar` para gerar o artefato `target/chrondb.jar` e preparar arquivos auxiliares para o GraalVM - - Para gerar o binário nativo localmente após rodar o build, execute `native-image @target/native-image-args -jar target/chrondb.jar -o target/chrondb_local` + - Para gerar o binário nativo localmente após rodar o build, execute `native-image @target/native-image-args -jar target/chrondb.jar -o target/chrondb_local`dev/chrondb/native_image.clj (2)
140-145: Gate -O0 and -H:-CheckToolchain with env vars (CI vs local).-O0 speeds builds but hurts runtime; -H:-CheckToolchain can hide misconfigs. Make them configurable.
- "-H:-CheckToolchain" - "-O0" ;; performance + (when (= "0" (System/getenv "NATIVE_CHECK_TOOLCHAIN")) "-H:-CheckToolchain") + (or (System/getenv "NATIVE_O") "-O0") ;; default O0; set NATIVE_O to e.g. -O3 for releasesNote: filter out nils before writing args (e.g., via remove nil?). For example:
(let [tail-args (->> [... (when ...) (or ...)] (remove nil?))] ...)
175-221: Optional: drop test-only class from reflect-config to reduce noise.org.apache.lucene.internal.tests.TestSecrets is a test-only class; referencing it can produce warnings during native-image.
- {:name "org.apache.lucene.internal.tests.TestSecrets" - :allDeclaredConstructors true - :allDeclaredMethods true}dev/chrondb/build.clj (1)
93-104: Warn when building thin jar (to avoid native-image classpath issues).If users forget --uberjar, native-image likely fails. Emit a clear warning.
(let [uberjar? (boolean (some #(= % "--uberjar") args)) basis (build-basis) options (build-options basis)] + (when-not uberjar? + (println "[WARN] Building a thin JAR. Native-image requires dependencies on the classpath or an uberjar. Consider passing --uberjar.")) (clean-target!)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.cursorrules(1 hunks).github/copilot-instructions.md(0 hunks).github/copilot-instructions.md(1 hunks).github/workflows/build-native-image.yml(1 hunks).gitignore(1 hunks)AGENT.md(1 hunks)CHANGELOG.md(1 hunks)deps.edn(2 hunks)dev/chrondb/build.clj(1 hunks)dev/chrondb/native_image.clj(1 hunks)docs/operations.md(1 hunks)src/chrondb/api/redis/core.clj(2 hunks)src/chrondb/api/server.clj(1 hunks)src/chrondb/api/sql/connection/server.clj(1 hunks)src/chrondb/core.clj(1 hunks)src/chrondb/storage/git/commit.clj(6 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Run SQL Protocol Benchmark
- GitHub Check: test
🔇 Additional comments (7)
src/chrondb/api/server.clj (1)
62-62: LGTM: Syntax correction applied.The extra closing parenthesis has been correctly removed.
src/chrondb/api/sql/connection/server.clj (1)
36-36: LGTM: Type hint improves native-image compilation.The
^ServerSockettype hint eliminates reflection and supports GraalVM native-image compilation.CHANGELOG.md (1)
9-9: LGTM: Changelog entry is accurate.The changelog appropriately documents the new GraalVM native binary support.
.github/workflows/build-native-image.yml (1)
32-35: Ignore missing -jar warning: args file includes the jar path. The build script (dev/chrondb/native_image.clj:122–128) injects-jar target/chrondb.jarinto native-image-args, so the workflow command is correct as-is.Likely an incorrect or invalid review comment.
src/chrondb/core.clj (1)
17-17: LGTM! Essential for GraalVM native-image support.The
:gen-classdirective enables AOT compilation and Java class generation, which is required for creating a native-image binary with a proper entry point. This aligns perfectly with the PR objectives to enable standalone binary distribution.src/chrondb/api/redis/core.clj (2)
535-535: LGTM! Type hint eliminates reflection.The
^ServerSockettype hint on the function parameter eliminates reflection on subsequent method calls (.isClosed,.accept), which is essential for GraalVM native-image compilation.
555-555: LGTM! Type hint eliminates reflection.The
^ServerSockettype hint on the local binding eliminates reflection on theServerSocket.constructor and ensures the type is known for the subsequentaccept-connectionscall.
| - uses: DeLaGuardo/setup-clojure@13.4 | ||
| with: | ||
| cli: 1.12.0.1530 | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} |
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.
🧩 Analysis chain
Verify GitHub Actions versions are current.
Consider checking if you're using the latest versions of the GitHub Actions:
DeLaGuardo/setup-clojure@13.4- Clojure CLI
1.12.0.1530
Search the web to confirm these are the latest stable versions:
🌐 Web query:
What is the latest version of DeLaGuardo/setup-clojure GitHub Action and Clojure CLI as of October 2025?
💡 Result:
-
DeLaGuardo/setup-clojure GitHub Action: v12.5. [1]
-
Clojure CLI (stable): 1.12.3 (tools release 1.12.3.1577). [2][3]
Sources:
[1] GitHub Marketplace — Setup Clojure (DeLaGuardo/setup-clojure). (github.com)
[2] Clojure downloads — Stable Release: 1.12.3 (Sep 25, 2025). (clojure.org)
[3] Clojure Tools releases (1.12.3.1577). (clojure.org)
Citations:
- 1: https://github.com/marketplace/actions/setup-clojure?utm_source=openai
- 2: https://clojure.org/releases/downloads?utm_source=openai
- 3: https://clojure.org/releases/tools?utm_source=openai
Update GitHub Action and Clojure CLI to latest stable versions.
- Replace
DeLaGuardo/setup-clojure@13.4with@v12.5 - Set Clojure CLI to
1.12.3.1577
🤖 Prompt for AI Agents
.github/workflows/build-native-image.yml lines 16-19: update the GitHub Action
and Clojure CLI version values; replace the action reference
DeLaGuardo/setup-clojure@13.4 with DeLaGuardo/setup-clojure@v12.5 and change the
cli version from 1.12.0.1530 to 1.12.3.1577, leaving the github-token usage
intact.
.gitignore
Outdated
| report/ | ||
| META-INF/*-native-image-args | ||
| .native-image/ | ||
|
|
||
| # GraalVM native-image artifacts | ||
| target/native/ | ||
| target/chrondb_* | ||
| chrondb_local | ||
|
|
||
| # OS | ||
| .DS_Store | ||
| Thumbs.db | ||
|
|
||
| # doc codox | ||
| docs/api/ | ||
| META-INF/ | ||
| .envrc | ||
| ./chrondb_local | ||
| ./chrondb_macos | ||
| ./chrondb_linux |
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.
🛠️ Refactor suggestion | 🟠 Major
Clean up duplicate and redundant ignore patterns.
Several issues with the new ignore patterns:
-
Duplicate entries:
chrondb_localappears at both line 28 and line 38 (with./prefix)META-INF/entries at lines 22 and 36
-
Redundant
./prefix:- Lines 38-40 use explicit
./prefix which is unnecessary in.gitignore(paths are relative to repository root by default)
- Lines 38-40 use explicit
Apply this diff to consolidate the patterns:
# Build
target/
data/
test-*
benchmark_results_*.txt
report/
-META-INF/*-native-image-args
.native-image/
# GraalVM native-image artifacts
target/native/
target/chrondb_*
chrondb_local
+chrondb_macos
+chrondb_linux
# OS
.DS_Store
Thumbs.db
# doc codox
docs/api/
META-INF/
.envrc
-./chrondb_local
-./chrondb_macos
-./chrondb_linux📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| report/ | |
| META-INF/*-native-image-args | |
| .native-image/ | |
| # GraalVM native-image artifacts | |
| target/native/ | |
| target/chrondb_* | |
| chrondb_local | |
| # OS | |
| .DS_Store | |
| Thumbs.db | |
| # doc codox | |
| docs/api/ | |
| META-INF/ | |
| .envrc | |
| ./chrondb_local | |
| ./chrondb_macos | |
| ./chrondb_linux | |
| # Build | |
| target/ | |
| data/ | |
| test-* | |
| benchmark_results_*.txt | |
| report/ | |
| .native-image/ | |
| # GraalVM native-image artifacts | |
| target/native/ | |
| target/chrondb_* | |
| chrondb_local | |
| chrondb_macos | |
| chrondb_linux | |
| # OS | |
| .DS_Store | |
| Thumbs.db | |
| # doc codox | |
| docs/api/ | |
| META-INF/ | |
| .envrc |
🤖 Prompt for AI Agents
In .gitignore around lines 21 to 40, there are duplicate and redundant patterns:
remove the duplicated META-INF/ and duplicate chrondb_local entry (the one with
./ prefix), and drop the unnecessary ./ prefixes on chrondb_macos and
chrondb_linux; consolidate entries so each ignore pattern appears once (e.g.,
keep META-INF/ once, keep chrondb_local without ./, and list chrondb_macos and
chrondb_linux without ./), preserving the rest of the ignore lines and ordering
as desired.
| :extra-paths ["dev"] | ||
| :main-opts ["-m" "chrondb.build"]} | ||
| :dev {:extra-paths ["dev"] |
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.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Build alias should produce an uberjar (native-image needs deps on classpath).
native-image-args currently use only target/classes + target/chrondb.jar. If the jar is thin (no deps), local native-image will fail. CI likely passes --uberjar, but AGENT.md instructs just -M:build.
Recommend making :build default to uberjar to reduce footguns.
Apply this diff:
- :main-opts ["-m" "chrondb.build"]}
+ :main-opts ["-m" "chrondb.build" "--uberjar"]}If you prefer not to force uberjar by default, at least update docs in AGENT.md to instruct using --uberjar.
🏁 Script executed:
#!/bin/bash
rg -nP '^\s*:aliases\s+\{' -C5 deps.edn
rg -nP '^\s*:build\s+\{' -C3 deps.ednLength of output: 1361
🏁 Script executed:
#!/bin/bash
# Locate and inspect build script
build_file=$(rg -l 'ns chrondb.build' -g '*.clj')
echo "Build script: $build_file"
rg -n 'defn -main' -C5 "$build_file"
rg -n ':uberjar' -C3 "$build_file"
# Locate and inspect AGENT.md
agent_file=$(find . -iname AGENT.md)
echo "Agent doc: $agent_file"
rg -n 'M:build' -C3 "$agent_file"
rg -n 'uberjar' -C3 "$agent_file"Length of output: 950
Force --uberjar in the :build alias
Add --uberjar to :main-opts in deps.edn so the default build produces an uberjar for native-image:
File: deps.edn
@@ -83,1 +83,1
- :main-opts ["-m" "chrondb.build"]}
+ :main-opts ["-m" "chrondb.build" "--uberjar"]}Alternatively, if you prefer not to change the alias, update AGENT.md to instruct using clojure -M:build -- --uberjar.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| :extra-paths ["dev"] | |
| :main-opts ["-m" "chrondb.build"]} | |
| :dev {:extra-paths ["dev"] | |
| :extra-paths ["dev"] | |
| :main-opts ["-m" "chrondb.build" "--uberjar"]} | |
| :dev {:extra-paths ["dev"] |
🤖 Prompt for AI Agents
In deps.edn around lines 83 to 85, the :build alias currently sets :main-opts
["-m" "chrondb.build"] but does not force building an uberjar; update the
:main-opts to include "--uberjar" (e.g. ["-m" "chrondb.build" "--uberjar"]) so
the default build produces an uberjar for native-image; alternatively, if you
prefer not to change the alias, update AGENT.md to instruct users to run clojure
-M:build -- --uberjar instead.
dev/chrondb/native_image.clj
Outdated
| path-sep (System/getProperty "path.separator") | ||
| classpath (string/join path-sep ["target/classes" "target/chrondb.jar"]) | ||
| base-args ["-Dorg.slf4j.simpleLogger.defaultLogLevel=info" | ||
| "-Dorg.slf4j.simpleLogger.log.org.eclipse.jetty.server=warn" | ||
| "--features=clj_easy.graal_build_time.InitClojureClasses" | ||
| "-H:+UnlockExperimentalVMOptions"] | ||
| startup-args ["-cp" classpath | ||
| "-jar" "target/chrondb.jar" | ||
| "-H:Class=chrondb.core"] | ||
| tail-args ["--enable-all-security-services" |
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.
Don’t mix -cp, -jar, and -H:Class; prefer a single mode.
Passing both -cp and -jar with -H:Class is redundant and can be confusing. If you’re building an uberjar, -jar is sufficient; drop -cp and -H:Class.
- path-sep (System/getProperty "path.separator")
- classpath (string/join path-sep ["target/classes" "target/chrondb.jar"])
+ ;; For uberjar builds, classpath is not needed
+ path-sep (System/getProperty "path.separator")
+ classpath (string/join path-sep ["target/classes" "target/chrondb.jar"])
base-args ["-Dorg.slf4j.simpleLogger.defaultLogLevel=info"
"-Dorg.slf4j.simpleLogger.log.org.eclipse.jetty.server=warn"
"--features=clj_easy.graal_build_time.InitClojureClasses"
"-H:+UnlockExperimentalVMOptions"]
- startup-args ["-cp" classpath
- "-jar" "target/chrondb.jar"
- "-H:Class=chrondb.core"]
+ startup-args ["-jar" "target/chrondb.jar"]If you need a thin-jar path, create two branches: one with ["-cp" computed-classpath "chrondb.core"] and one with ["-jar" ...], selected based on an env var or presence of an uberjar.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| path-sep (System/getProperty "path.separator") | |
| classpath (string/join path-sep ["target/classes" "target/chrondb.jar"]) | |
| base-args ["-Dorg.slf4j.simpleLogger.defaultLogLevel=info" | |
| "-Dorg.slf4j.simpleLogger.log.org.eclipse.jetty.server=warn" | |
| "--features=clj_easy.graal_build_time.InitClojureClasses" | |
| "-H:+UnlockExperimentalVMOptions"] | |
| startup-args ["-cp" classpath | |
| "-jar" "target/chrondb.jar" | |
| "-H:Class=chrondb.core"] | |
| tail-args ["--enable-all-security-services" | |
| ;; For uberjar builds, classpath is not needed | |
| path-sep (System/getProperty "path.separator") | |
| classpath (string/join path-sep ["target/classes" "target/chrondb.jar"]) | |
| base-args ["-Dorg.slf4j.simpleLogger.defaultLogLevel=info" | |
| "-Dorg.slf4j.simpleLogger.log.org.eclipse.jetty.server=warn" | |
| "--features=clj_easy.graal_build_time.InitClojureClasses" | |
| "-H:+UnlockExperimentalVMOptions"] | |
| startup-args ["-jar" "target/chrondb.jar"] | |
| tail-args ["--enable-all-security-services" |
🤖 Prompt for AI Agents
In dev/chrondb/native_image.clj around lines 121 to 130, the command-line args
mix "-cp", "-jar", and "-H:Class" which is redundant/conflicting; choose a
single invocation mode. Remove "-cp" and "-H:Class" when using the uberjar
"-jar" form (keep startup-args as ["-jar" "target/chrondb.jar"]), or
alternatively provide a second branch that uses the thin-jar/classpath form
(startup-args ["-cp" computed-classpath "chrondb.core"]) and select between them
via an env var or by detecting the presence of the uberjar; update code to pick
one branch and eliminate the conflicting flags.
| ### GraalVM Native Image | ||
|
|
||
| ChronDB pode ser distribuído como binário compilado via GraalVM: | ||
|
|
||
| 1. Instale GraalVM com o componente `native-image` | ||
| 2. Rode `clojure -M:build -- --uberjar` para gerar `target/chrondb.jar` e arquivos auxiliares | ||
| 3. Execute `native-image @target/native-image-args -jar target/chrondb.jar -o target/chrondb_local` | ||
| 4. Teste o binário local: `./target/chrondb_local` | ||
|
|
||
| O workflow `build-native-image.yml` (GitHub Actions) executa o mesmo processo e publica os artefatos por sistema operacional. |
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.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Fix language inconsistency and verify command accuracy.
Two issues with this section:
-
Language inconsistency: Line 143 and subsequent text are in Portuguese while the rest of the document is in English. Please translate to English for consistency.
-
Command discrepancy with workflow: Line 147's native-image command differs from the workflow at
.github/workflows/build-native-image.ymlline 35:- Docs:
native-image @target/native-image-args -jar target/chrondb.jar -o target/chrondb_local - Workflow:
native-image @native-image-args -H:Name=chrondb_${{ runner.os }}(executed fromtarget/directory)
- Docs:
The workflow doesn't explicitly specify -jar or the jar path. Verify that the args file contains these parameters, or update the docs to match the workflow command.
Run the following script to check if native-image-args contains jar specifications:
🏁 Script executed:
#!/bin/bash
# Check if native-image-args file will be generated with jar path
rg -n "native-image-args|chrondb.jar" dev/chrondb/Length of output: 342
🏁 Script executed:
#!/bin/bash
# Inspect the flags written to native-image-args
sed -n '140,220p' dev/chrondb/native_image.cljLength of output: 5065
Translate to English and align native-image command
- Replace the Portuguese header and description with English, e.g.:
“ChronDB can be distributed as a GraalVM native image:” - Change step 3 to mirror the workflow’s invocation, for example:
cd target && native-image @native-image-args -H:Name=chrondb_local
🤖 Prompt for AI Agents
In docs/operations.md around lines 141 to 150, the GraalVM native-image section
is in Portuguese and the native-image invocation differs from the workflow;
translate the header and descriptive sentence to English (e.g., "ChronDB can be
distributed as a GraalVM native image:") and update step 3 to match the GitHub
Actions workflow by changing it to instruct the user to cd into the target
directory and run native-image using the @native-image-args file and the -H:Name
option to produce chrondb_local (i.e., align the CLI invocation with the
workflow).
| (when head-id | ||
| (let [tree-walk (TreeWalk. (.getRepository git)) | ||
| h-idx (.addTree tree-walk (.parseTree (RevWalk. (.getRepository git)) head-id))] | ||
| (let [^Repository repo (.getRepository git) | ||
| tree-walk (TreeWalk. repo) | ||
| h-idx (.addTree tree-walk (.parseTree (RevWalk. repo) head-id))] | ||
| (.setRecursive tree-walk true) |
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.
Close RevWalk in create-temporary-index (resource leak).
A new RevWalk is created but never closed. Wrap it and close in finally.
- (let [^Repository repo (.getRepository git)
- tree-walk (TreeWalk. repo)
- h-idx (.addTree tree-walk (.parseTree (RevWalk. repo) head-id))]
+ (let [^Repository repo (.getRepository git)
+ tree-walk (TreeWalk. repo)
+ rev-walk (RevWalk. repo)
+ h-idx (.addTree tree-walk (.parseTree rev-walk head-id))]
(.setRecursive tree-walk true)
...
- (.close tree-walk)))
+ (.close tree-walk)
+ (.close rev-walk)))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| (when head-id | |
| (let [tree-walk (TreeWalk. (.getRepository git)) | |
| h-idx (.addTree tree-walk (.parseTree (RevWalk. (.getRepository git)) head-id))] | |
| (let [^Repository repo (.getRepository git) | |
| tree-walk (TreeWalk. repo) | |
| h-idx (.addTree tree-walk (.parseTree (RevWalk. repo) head-id))] | |
| (.setRecursive tree-walk true) | |
| (when head-id | |
| (let [^Repository repo (.getRepository git) | |
| tree-walk (TreeWalk. repo) | |
| rev-walk (RevWalk. repo) | |
| h-idx (.addTree tree-walk | |
| (.parseTree rev-walk head-id))] | |
| (.setRecursive tree-walk true) | |
| ;; … existing code using tree-walk … | |
| (.close tree-walk) | |
| (.close rev-walk))) |
🤖 Prompt for AI Agents
In src/chrondb/storage/git/commit.clj around lines 117 to 121, a RevWalk is
instantiated for parsing the tree (RevWalk. repo) but never closed, causing a
resource leak; modify the code to ensure the RevWalk is closed after use by
wrapping its creation/usage in a try/finally or using Clojure's with-open (or
equivalent) so that .close is always called after .parseTree completes, and keep
the existing TreeWalk logic intact.
- update Clojure CLI to 1.12.3.1577 in build workflow for better compatibility - update .gitignore for GraalVM native image artifacts and META-INF/ - prep for native-image builder and Docker integration Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
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.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/build-native-image.yml(1 hunks).gitignore(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/build-native-image.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Run SQL Protocol Benchmark
- GitHub Check: test
- GitHub Check: test
🔇 Additional comments (2)
.gitignore (2)
30-30: LGTM: Ignore local direnv file.
.envrcshould be ignored.
33-33: LGTM: Ignore generated docs.
docs/api/belongs in .gitignore.
| report/ | ||
| .native-image/ | ||
| chrondb_* | ||
| META-INF/ | ||
| target/native/ |
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.
Don't ignore META-INF globally — it will hide GraalVM configs.
META-INF/ matches in any directory and would exclude resources/META-INF/native-image/** (e.g., reflect-config.json, resource-config.json) requested by the native-image work. Remove it. While here, minor cleanups:
target/native/is redundant (already covered bytarget/).- Scope
chrondb_*to repo root to avoid unintended ignores in subdirs.
Apply within these lines:
report/
.native-image/
-chrondb_*
-META-INF/
-target/native/
+/chrondb_*
+# Do not ignore META-INF globally; needed for native-image configs
+# target/native/ is already covered by target/📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| report/ | |
| .native-image/ | |
| chrondb_* | |
| META-INF/ | |
| target/native/ | |
| report/ | |
| .native-image/ | |
| /chrondb_* | |
| # Do not ignore META-INF globally; needed for native-image configs | |
| # target/native/ is already covered by target/ |
🤖 Prompt for AI Agents
In .gitignore around lines 21 to 25, remove the global "META-INF/" entry (it
hides GraalVM native-image configs under resources/META-INF/native-image/),
delete the redundant "target/native/" line (target/ already covers it), and
change the unconstrained "chrondb_*" to be repo-root scoped (prepend a leading
slash: "/chrondb_*") so it doesn't ignore similarly named files in
subdirectories; keep the other entries (report/ and .native-image/) as-is and
apply these edits within the specified lines.
- Introduce Dockerfile supporting GraalVM native-image builds targeting ChronDB native binaries - Includes Clojure 1.12 JVM toolchain with build steps for `chrondb.jar` and native artifact - Prepares container for production runtime with restricted user and required system libs - exposes ChronDB ports (3000, 6379, 5432) - updates native-image invocation to leverage generated `target/native-image-args` with proper GraalVM options for Clojure and JGit compatibility - first step for containerized, reproducible native deployment Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
- Expanded AGENT.md to provide a detailed ChronDB Agent Guide, covering project overview, code style, development guidelines, Git-based architecture, native image/Docker workflows, and documentation standards. - Updated Dockerfile for improved clarity, reproducibility, and alignment with build/runtime best practices: - Separated builder/runtime stages, with explicit installation of Clojure and toolchain components. - Ensured correct inclusion of resources, user permissions, data directory, and exposed ports. - Native image build instructions clarified to support GraalVM and closed-world constraints required for JGit-based persistence. - This change enforces Clojure idioms, preserves chronological commit immutability, and documents native- and container-related procedures in depth for both developers and operators. No application logic was changed; all updates are developer-facing material and build infrastructure. Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
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.
Actionable comments posted: 1
♻️ Duplicate comments (2)
dev/chrondb/native_image.clj (2)
227-229: Don't mix -cp, -jar, and -H:Class; prefer a single mode.Passing both
-cpand-jarwith-H:Classis redundant and can be confusing. For uberjar builds,-jaris sufficient.Apply this diff to use only the jar-based invocation:
- startup-args ["-cp" classpath - "-jar" jar-path - "-H:Class=chrondb.core"] + startup-args ["-jar" jar-path]Based on learnings
289-293: Remove redundant fallback configuration creation.This fallback logic creates
reflect-config.jsonandresource-config.jsononly if they don't exist, but lines 287-288 already wrote these files with proper content. The fallback is redundant and should be removed.Apply this diff:
- (doseq [[fname contents] [["reflect-config.json" "[]"] - ["resource-config.json" (json/write-str {:resources {:includes []}})]]] - (let [file (io/file native-config-dir fname)] - (when-not (.exists file) - (spit file contents)))) + )) - nil))
🧹 Nitpick comments (2)
Dockerfile (1)
17-18: Consider adding error handling for build dependencies.The build assumes
target/native-image-argsexists. If the file is missing or malformed, the native-image build will fail without a clear error message.Consider adding a verification step:
+RUN test -f target/native-image-args || (echo "Error: native-image-args not found" && exit 1) + RUN clojure -M:build -- --uberjar && \ native-image @target/native-image-args -H:Name=chrondbdev/chrondb/native_image.clj (1)
131-134: Clarify the purpose of the empty filter set.The
clojure-initializersfunction uses an empty set for filtering, which will always return an empty vector. If this is intentional (no special runtime initializers needed), consider removing the function or adding a comment explaining why the filter is empty.If no special initializers are needed:
-(defn- clojure-initializers - [classes] - (let [targets #{}] - (vec (filter targets classes)))) +(defn- clojure-initializers + [classes] + ;; No special runtime initializers required for clojure.lang classes + [])
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
AGENT.md(1 hunks)Dockerfile(1 hunks)dev/chrondb/native_image.clj(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- AGENT.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test
- GitHub Check: Run SQL Protocol Benchmark
- GitHub Check: test
🔇 Additional comments (10)
Dockerfile (2)
37-37: Document the purpose of multiple exposed ports.Exposing three ports (3000, 6379, 5432) suggests multiple protocol support. While this may be intentional, ensure each port is documented and secured appropriately, as multiple exposed ports increase the attack surface.
Consider verifying which protocols are actually implemented and whether all ports need to be exposed by default.
31-35: LGTM!The non-root user setup follows security best practices with proper ownership and restricted shell access.
dev/chrondb/native_image.clj (8)
1-6: LGTM!Namespace and imports are properly structured.
8-108: LGTM!The class lists for build-time and run-time initialization are well-organized and appropriate for GraalVM native-image compilation.
112-129: LGTM!The function correctly extracts
clojure.lang.*classes from the JAR and handles the missing file case gracefully.
136-184: LGTM!The reflection configuration properly exposes necessary constructors, methods, and fields for JGit, Lucene, and Jetty classes.
186-197: LGTM!Helper functions are simple and correct. The
macos-sdk-rootfunction properly handles exceptions andensure-dir!ensures directory existence.
199-226: LGTM!The setup phase correctly creates directories, detects the macOS SDK, and processes Clojure classes to separate build-time and run-time initialization.
230-275: LGTM!The native-image arguments are comprehensive and include appropriate debugging options, trace configurations, and security settings.
276-288: LGTM!The reflection and resource configuration files are properly generated with appropriate patterns for JGit, Clojure, and META-INF resources.
- Added section in AGENT.md describing the new `publish-docker.yml` workflow for automated Docker image publishing to GitHub Container Registry. - Documented authentication, build, and push details for Docker CI in project docs. - Updated Dockerfile to use `ghcr.io/graalvm/native-image:ol9-java17-22` (removing patch version for wider compatibility with upstream image updates). - Ensured all CI/CD and native image notes comply with project conventions and explain rationale for each pipeline change. fixed: #57 (comment) Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
- Introduce `.github/workflows/publish-docker.yml` for automated Docker image build and publish.
- Builds using project Dockerfile and pushes latest tag to GitHub Container Registry.
- Authenticates via `${{ secrets.GITHUB_TOKEN }}` with package write permissions.
- Ensures every push to `main` branch publishes up-to-date image for streamlined deployments.
Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
- Added section in AGENT.md describing the new `publish-docker.yml` workflow for automated Docker image publishing to GitHub Container Registry. - Documented authentication, build, and push details for Docker CI in project docs. - Updated Dockerfile to use `ghcr.io/graalvm/native-image:ol9-java17-22` (removing patch version for wider compatibility with upstream image updates). - Ensured all CI/CD and native image notes comply with project conventions and explain rationale for each pipeline change. fixed: #57 (comment) Signed-off-by: Avelino <31996+avelino@users.noreply.github.com>
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.
Actionable comments posted: 0
♻️ Duplicate comments (1)
Dockerfile (1)
1-4: Update builder image to a supported GraalVM tag
ghcr.io/graalvm/native-image:ol9-java17-22is from 2022 and no longer receives CPU/security fixes. The supported images have moved toghcr.io/graalvm/native-image-community, and hard-coding the 22.3.2 path inPATHblocks future upgrades. Switch to the current community image and drop the version-specific PATH to keep native-image on PATH while staying patched.-FROM ghcr.io/graalvm/native-image:ol9-java17-22 AS builder - -ENV CLOJURE_VERSION=1.12.3.1577 \ - PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/graalvm-ce-java17-22.3.2/bin:$PATH" +FROM ghcr.io/graalvm/native-image-community:17-ol9 AS builder + +ENV CLOJURE_VERSION=1.12.3.1577
🧹 Nitpick comments (2)
.github/workflows/publish-docker.yml (1)
36-45: Tag images with the commit SHA for traceabilityPublishing only
latestmakes it impossible to trace or roll back specific builds. Add a commit SHA tag so every push yields an immutable reference.- tags: type=raw,value=latest + tags: | + type=raw,value=latest + type=shaAGENT.md (1)
124-130: Update docs to match the supported builder imageThe Docker instructions still point to
ghcr.io/graalvm/native-image:ol9-java17-22.3.2. Once the Dockerfile switches to the community tag, please update this section to referenceghcr.io/graalvm/native-image-community:17-ol9so the guide reflects the actual build base.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
.github/workflows/publish-docker.yml(1 hunks)AGENT.md(1 hunks)Dockerfile(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Run SQL Protocol Benchmark
- GitHub Check: test
- GitHub Check: test
build-native-image.ymlfor GraalVM native-image binary builds on macOS and Ubuntu.gitignorefor native-image build artifacts and outputsMotivation:
Enables efficient cross-platform deployments and easier distribution of ChronDB as a native binary, improving startup time and resource usage, especially for cloud and container environments.
Related:
dev/chrondb/native_image.clj, build script, updated ignore rulesfixed: #12
Summary by CodeRabbit
New Features
Documentation
Chores