Skip to content

feat: use a build file (pom.xml / build.gradle / build.sbt / build.mill) as a JBang dependency - #2657

Open
maxandersen wants to merge 1 commit into
jbangdev:mainfrom
maxandersen:builddeps
Open

feat: use a build file (pom.xml / build.gradle / build.sbt / build.mill) as a JBang dependency#2657
maxandersen wants to merge 1 commit into
jbangdev:mainfrom
maxandersen:builddeps

Conversation

@maxandersen

Copy link
Copy Markdown
Collaborator

Experimental: use a build file as a JBang dependency

Supersedes #2597 (which only covered Maven + Gradle and lacked caching, integration tests, and remote-script safeguards). Addresses #449 and #43.

Adds an experimental //DEPS <build-file> (and --deps <build-file>) syntax that lets a script reuse the compile dependencies declared in a real project's build file. JBang invokes the matching build tool, extracts the compile classpath, caches it, and adds the entries to the script's classpath.

//DEPS pom.xml
//DEPS build.gradle       // or build.gradle.kts
//DEPS build.sbt
//DEPS build.mill         // or build.mill.yaml / build.sc
//DEPS ^pom.xml           // walk upward from the script's dir

Command-line form:

jbang --deps pom.xml app.java
jbang --deps ^pom.xml src/main/java/app.java

What changed vs #2597

  • Strategy pattern. BuildSystem interface + one class per tool (MavenBuildSystem, GradleBuildSystem, SbtBuildSystem, MillBuildSystem). Shared plumbing (subprocess runner, wrapper detection, JBANG_CLASSPATH= marker) lives in BuildTools. Adding a fifth tool is a new class + one line in a registry.
  • sbt and Mill support added. Mill uses its native --disable-ticker show compileClasspath and understands the qref:vN:HASH:PATH / ref:vN:HASH:PATH entry format. sbt uses export Compile / dependencyClasspath with output validation.
  • Filesystem cache keyed by build-file path + mtime + size, invalidated automatically when referenced jars disappear (e.g. wiped local repo). Clearable via jbang cache clear --projects.
  • CLI --deps path resolution fixed to resolve relative to CWD instead of the script's directory. Previously jbang --deps pom.xml properties@jbangdev looked for pom.xml in the catalog cache dir. Regression test included.
  • Remote-script rejection. Embedded //DEPS build.gradle in a script fetched from a URL/catalog is rejected up front with an actionable error, instead of silently trying to resolve against the download cache.
  • Ant dropped. No standard compile-classpath convention; supporting it required project-specific build.xml edits, which isn't worth the surface area.
  • Real fixtures + integration tests. itests/builddeps/<tool>/ for each supported tool with a pom.xml / build.gradle / build.sbt / build.mill, a src/main/java/example/Greeter.java project class, and a mise.toml declaring the tool version needed. BuildSystemClassPathsIT uses mise install + mise exec to run each tool for real; skips cleanly when mise isn't installed. Mill ships its official ./mill bootstrap script the way real Mill projects do.
  • Docs get a proper "Why", a per-tool support table, caching behavior, and a limitations section.

Known scope limitation (feedback wanted)

Only the project's declared compile dependencies are added — the project's own compiled classes are not. If you need to reference the project's source from a script, pull the files in with //SOURCES:

//DEPS pom.xml
//SOURCES src/main/java/example/Greeter.java

A future release may add a scope option (compile vs runtime) so the project's own output can be included automatically. Which scope should be the default? Feedback welcome — comment below.

Security

Build files can execute code. This is called out in the docs and is why the feature is marked EXPERIMENTAL. Only use with build files you trust.

Testing

  • Unit tests (TestBuildSystemClassPaths): 11 tests covering per-strategy dispatch, ^ lookup, CWD-based CLI resolution, cache hit/miss, remote-script rejection, and failure paths.
  • Integration tests (BuildSystemClassPathsIT): all four tools exercised end-to-end via mise — passes on my machine, skips when mise isn't installed.
  • spotlessCheck clean.

@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • ai-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 3f1fa456-49fa-4176-8476-ea5d264572a8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Adds an experimental //DEPS syntax that lets a script depend on a
build file (pom.xml, build.gradle[.kts], build.sbt, build.mill,
build.mill.yaml, build.sc). JBang invokes the matching build tool
and adds its compile classpath to the script's classpath. Works from
//DEPS directives in local scripts and from --deps on the command
line.

Design
------
* Strategy pattern: BuildSystem interface + one class per tool
  (Maven, Gradle, sbt, Mill). BuildTools holds the shared subprocess
  runner, wrapper-script detection, and JBANG_CLASSPATH= marker
  helpers. BuildSystemClassPaths coordinates dispatch, path
  resolution, and caching.
* Wrappers are preferred over global tools (mvnw, gradlew, ./mill).
* Resolved classpaths are cached under
  $JBANG_DIR/cache/projects/buildclasspaths/ keyed by build file
  path + mtime + size, with a jar-existence sanity check to
  invalidate stale entries when the local repo has been wiped.
  Clear with `jbang cache clear --projects`.

Tool-specific handling
----------------------
* Maven: `dependency:build-classpath` with an output file so we
  never have to parse Maven's log.
* Gradle: a temporary init script registers `jbangPrintClasspath`
  on any subproject with the `java` plugin. Fails loudly if no
  such subproject exists, instead of silently returning empty.
* sbt: `sbt --error --batch "export Compile / dependencyClasspath"`
  with output validated to look like a classpath (contains
  File.pathSeparator or ends with .jar).
* Mill: `mill --disable-ticker show compileClasspath`; parses the
  JSON output while ignoring log lines and JVM `sun.misc.Unsafe`
  warnings that also contain `[`, and strips Mill's
  `qref:vN:HASH:` / `ref:vN:HASH:` entry prefixes.

Path resolution
---------------
* Script-embedded `//DEPS build.gradle` is resolved relative to the
  script file.
* CLI `--deps build.gradle` is resolved relative to CWD (previously
  resolved to the script's directory, which for remote/aliased
  scripts is a cache dir under ~/.jbang/cache/urls/).
* `//DEPS ^pom.xml` uses `Util.findNearestWith` to walk up from the
  script's directory to find the file.
* Embedded build-file deps in remote/URL-based scripts are rejected
  up front with an actionable error rather than trying to resolve
  them against the download cache.

Ant is not supported (no standard compile-classpath convention).

Tests
-----
* Unit tests in TestBuildSystemClassPaths cover each strategy via
  wrapper-script stubs, `^` lookup, CWD-based CLI resolution, cache
  behavior, remote-script rejection, and failure paths.
* Integration tests in BuildSystemClassPathsIT exercise all four
  real build tools using fixtures under `itests/builddeps/<tool>/`.
  Each fixture ships a `mise.toml` declaring the tool it needs; the
  IT runs `mise install` per fixture and then `mise exec` to invoke
  jbang with the declared tools on PATH. Tests skip cleanly when
  mise is not installed. Mill ships its official bootstrap script
  (`./mill`) in the fixture, matching how real Mill projects work.

Docs
----
`docs/modules/ROOT/pages/running.adoc` now has a dedicated section
with a "Why" motivation, a per-tool support table, caching
behavior, and limitations.
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

📦 PR Build Available

Install this PR build:

curl -sL https://github.com/jbangdev/jbang-pr-builds/releases/download/pr-2657/jbang.tar | tar xf - && ./jbang/bin/jbang version

Release
| Built from ea81e3f

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