Skip to content

3.0.0

Latest

Choose a tag to compare

@gbevin gbevin released this 10 Sep 06:28
· 6 commits to main since this release

This release makes bld resolve and transfer dependencies in parallel, adds
bill of materials support, and lets AI agents drive a build through the Model
Context Protocol. It also drops the retired Sonatype OSSRH repositories and
changes a handful of API signatures in ways that break binary compatibility
for already compiled callers, which together are what make this a major
version.

Dependency resolution and transfers

  • Artifact transfers now run in parallel, with live progress in an interactive terminal and a single stable line per finished transfer in CI logs, pipes and IDE consoles. The number of parallel transfers is set with the bld.transferParallelism property and defaults to 6, 1 makes them sequential again.
  • Transitive dependency resolution runs in parallel with speculative POM prefetching, through the new ParallelDependencyResolver and PomPrefetcher. The number of parallel POM retrievals is set with the bld.resolutionParallelism property and defaults to 6, 1 disables the speculative retrieval.
  • updates and the resolution of wrapper extensions are parallelized as well.
  • The download command and the wrapper extension resolver announce the analysis before it starts, with an Analyzing dependencies... line and a separate one for the bld extensions, so a long resolution doesn't look like a pause.
  • The download command batches the artifact transfers of all its scopes into a single DependencyTransferBatch, so that one pass fills the whole lib directory instead of one pass per scope.
  • Transient retrieval failures are retried and the artifact retrieval connections are bounded by connect and read timeouts. A repository that fails transiently, or that serves a POM that doesn't parse, falls through to the next repository instead of failing the resolution.
  • Added the GOOGLE_MAVEN_CENTRAL, GOOGLE_MAVEN_CENTRAL_EU and GOOGLE_MAVEN_CENTRAL_ASIA repository mirrors.
  • Added dependencyClasspathJars and extensionClasspathJars to BaseProject, which return the jars of a single dependency together with its transitive compile and runtime dependencies. The resolved classpaths are cached in the bld cache and come from the actual artifact transfers, so that a custom command can build an isolated classpath without resolving anything a second time once the cache holds them.
  • Local dependencies and local modules can be specified with an absolute path, and local and localModule accept a File or a Path next to a String.
  • Added DependencySet.include(DependencySet) to include a whole set at once, which carries the local dependencies, the local modules and the BOMs along with the dependencies. The copy constructor goes through it, where it used to copy the dependencies alone.

Bill of materials

  • Added bill of materials support through Bom and the bom(...) methods. A dependency that is declared without a version takes its version from a BOM, and a transitive dependency that matches a BOM entry is pinned to it. A bld.override property always wins, followed by a version that is explicitly declared in the build file, followed by a BOM. A dependency that is declared without a version and that neither an override nor an applicable BOM covers still resolves to its latest version.
  • BOMs apply across scopes the way classpaths do, a scope-local BOM takes precedence over an inherited one, and inherited BOMs follow the standard scope order.
  • For the scopes that a BOM applies to, the download command reports the version-less dependencies that neither those BOMs nor an override cover, and warns when a declared version differs from the version an applicable BOM supplies, or when two BOMs supply conflicting versions for the same dependency.
  • Published POMs carry a dependencyManagement section with the BOMs declared in the scopes that get published, which are compile, runtime and provided. A BOM declared for test or standalone stays out of the POM.

AI agents

  • Added experimental MCP support through the new mcp command, which serves the build commands of a project as Model Context Protocol tools over the stdio transport. The mcp command itself is never served, and a build can exclude others. Invoking a tool runs the command as a separate build process, with its console output captured separately from the protocol streams.
  • Tool results carry structured content with execution metadata, and the console output of a running command is streamed as log message notifications instead of arriving in one block when the command ends.
  • The project layout, the declared dependencies and the transitive dependency tree are served as MCP resources.
  • ./bld mcp install registers the project with an MCP client by writing the configuration file inside the project directory: .mcp.json for Claude Code and compatible clients, .cursor/mcp.json for Cursor and .vscode/mcp.json for VS Code. The server entry is merged into an existing configuration file rather than replacing it, so the other servers in that file stay, and --print prints the configuration instead of writing it.
  • The publish command is flagged as needing explicit human confirmation and marked destructive in its tool annotations. That is advisory metadata for the client, the server doesn't block the call itself. requireConfirmation, excludeCommand, toolCallTimeout and outputLimit configure that side of the server.
  • Added the --use-stderr option, which redirects the standard output of the wrapper and of the build to standard error, so that standard output stays free for the protocol while the build starts up.

Command line

  • Added the --verbose option, with -v as its short form, which closes #67.
  • Added the --auto-download-purge option, which turns on the behavior of the autoDownloadPurge project option for a single invocation.
  • Fixed #95: the help welcome message displays the Java version and vendor that bld is running on.
  • Added BuildExecutor.verbose, BuildExecutor.showStacktrace, BuildExecutor.offline and AbstractOperation.verbose setters, so that the verbose, stacktrace and offline state can also be set from build logic.
  • Added BuildExecutor.resolveCommand, which exposes the command matching of the command line, including its unique prefix and fuzzy matches.

Operations

  • Added the instrument command and InstrumentOperation, which applies RIFE2's bytecode transformations ahead of time as an alternative to the java agent. Ahead-of-time instrumented classes make continuations, meta-data merging and lazy loading work inside a GraalVM native image.
  • JavacOptions gained -Xlint options, --add-exports, --add-reads, --patch-module, --default-module-for-created-files, --source and --target, and the path list options now accept varargs and collections of String, File and Path. Null and empty values are consistently filtered out instead of ending up on the command line.
  • Fixed JavacOptions.containsRelease, which checked for -release instead of --release.
  • classpath and modulePath on the process operations accept File varargs and collections.
  • Fixed #66: compiling reports when no source files are found.
  • Fixed #69: running reports when no main class or module is specified.

Wrapper

  • The wrapper retries transient download failures instead of failing the build on the first one.
  • The wrapper jar contains the nested wrapper types and the RIFE2/core Product class, so that its user agent is formatted the same way the rest of bld formats it.
  • The RIFE2 agent jar is located by its resolved name, which is what a snapshot version needs.

Publishing

  • Repository names that a build file passes to PublishOperation.repository are resolved when the publication runs instead of when the build file is constructed, so that resolving them doesn't affect every other command.
  • A repository name that isn't declared is reported as a warning and skipped, instead of becoming a repository at that relative path. A bld.repo. property whose value isn't a location is refused outright.
  • publish-local no longer reaches the repositories that a build file names, it publishes to the local Maven repository only.
  • Added PublishOperation.clearRepositories, which clears both the repositories that were given as instances and the names that are still to be resolved.
  • Added PublishOperation.dependencyRepositories, so that the repositories that resolve versions during publication can be set separately.
  • Dependencies that are declared without a version are frozen to a concrete version in the published POM, so that the POM is always complete. One that a BOM covers stays version-less and takes its version from the dependency management section, unless the flattened dependency management would supply a different version than the BOMs that apply to its scope, or a bld.override supplies it, since the POM can reflect neither.

Project and CI

  • Added a release train that releases bld, RIFE2, RIFE2/core and the extensions together, described in RELEASE-TRAIN.md, together with a rehearsal sandbox that runs the whole thing against local repositories and remotes.
  • Added a workflow for publishing snapshot builds between releases, run by hand when one is wanted.
  • The CI workflow was reworked into a modular design that configures databases, images and credentials through the matrix, with dependency caching and the bld JUnit reporter.
  • Added CONTRIBUTING.md and an llms.txt file for discovery.

Other

  • The bld cache is stored as UTF-8. The cached dependency trees contain box drawing characters that the platform charset can't encode on every JVM.
  • bld runs on Java 17 and later, and is tested on Java 17, 21, 25 and 26.
  • Updated to latest dependencies. The project blueprints moved to JUnit 6.1.3, RIFE2 1.10.0, Jetty 12.1.12 and jsoup 1.23.2.

Compatibility notes

  • Several JavacOptions methods changed signature without keeping the old ones: addModules and modulePath take a Collection where they took a List, and moduleSourcePath, processorPath and their siblings take varargs where they took a single File, Path or String. Calls in source keep compiling, but an extension compiled against 2.3.0 that calls one of the affected signatures needs rebuilding to avoid a NoSuchMethodError.
  • The retired Sonatype OSSRH repositories were removed. SONATYPE_RELEASES, SONATYPE_RELEASES_LEGACY, SONATYPE_SNAPSHOTS and SONATYPE_SNAPSHOTS_LEGACY no longer exist, as constants or as repository names. Use CENTRAL_SNAPSHOTS for snapshots and publish releases through the Central Portal.
  • The project blueprints declare CENTRAL_SNAPSHOTS where they used to declare SONATYPE_SNAPSHOTS, so a newly created project points at Central snapshots.
  • Artifact transfers happen in parallel, so the order of the download lines is no longer the order the dependencies are declared in, and an interactive terminal gets a live updating block instead of a line per transfer. Set bld.transferParallelism=1 to transfer them one at a time again, which restores the order but not the old output.
  • Published POMs changed. A dependency that is declared without a version now carries a concrete version unless a published BOM import supplies it, and a project that declares BOMs in the compile, runtime or provided scopes now emits a dependencyManagement section.
  • publish-local no longer publishes to the repositories that the build file names. A build file that relied on that to reach a remote repository has to call publish instead.
  • PublishOperation.repository(String) no longer resolves the name when it is called, so a name that isn't declared is reported when the publication runs rather than when the build file is constructed. Because the names live in their own list until then, PublishOperation.clearRepositories() is what clears a publication's repositories, clearing the repositories() list alone leaves the names.
  • A location has to be an absolute path or a URL. A relative path is no longer taken as one, so a build file that named one as a repository now has it treated as an undeclared name and skipped.
  • A repository name that isn't declared is now reported as a warning and skipped. In 2.3.0 it became a repository at that relative path, so publishing to a name that was never declared wrote into a directory instead of saying so. A bld.repo. property that doesn't hold a location is now refused with a RepositoryLocationInvalidException.
  • The bld cache file is read and written as UTF-8.