Bundle a Temurin JRE in the VS Code extension - #11
Merged
lwrage merged 1 commit intoSep 21, 2026
Merged
Conversation
The extension had no Java of its own: it declared redhat.java as an extension dependency and launched the server with that extension's tooling JRE. Our server's runtime was therefore somebody else's implementation detail, a Red Hat change to javaRequirement.tooling_jre would break us, and the integration tests had to install redhat.java from the Marketplace just to activate - so the activation suite skipped itself, silently, whenever that failed. Bundle an Eclipse Temurin 21 JRE and run only that. There is no discovery, no JAVA_HOME or PATH fallback and no override setting, because one supported runtime is what makes a user's failure reproducible. JAVA_TOOL_OPTIONS, _JAVA_OPTIONS and JDK_JAVA_OPTIONS are dropped from the server's environment for the same reason: bundling a runtime and then letting the machine inject agents into it would defeat the point. A bundled runtime is platform-specific, so there is no longer a universal package. vsce packages one VSIX per platform - macOS, Linux and Windows on x64 and arm64 - and the Marketplace serves the matching one. Clients on a platform we do not build for, meaning Alpine, 32-bit ARM and the web, are offered nothing; that is a deliberate trade for not shipping six runtimes to every user. osate-cli already bundled these runtimes, so the download, checksum verification and unpacking now live in one shared helper. The osate-cli path gains the checksum verification it never had. Notes on two things that bite: - maven-clean follows the runtime symlink and deletes the cached JRE's contents even with followSymlinks=false, because the fileset directory is the link, so runtime/ is deliberately not cleaned. - unzip -l piped into grep -q fails under pipefail: grep exits at the first match and the SIGPIPE kills unzip, which reported a missing runtime that was present. The content checks use grep -c. Activation no longer rejects when the runtime cannot start. It reported nothing but a generic activation failure, which is no way to discover that a package was built for another platform. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #10: this branch builds on its commits (the advanced OSATE pin and its
scripts/build-test-releasechanges). Retarget tomainonce #10 merges.Why
The extension shipped no Java. It declared
redhat.javaas anextensionDependencyand launched the server with that extension's tooling JRE, which made our server's
runtime someone else's implementation detail — a change to
javaRequirement.tooling_jrebreaks us, and the Java version was outside ourcontrol. The integration tests had to install
redhat.javafrom the Marketplacejust to activate, so the activation suite was
this.skip()-gated and passedsilently whenever that failed.
What
JAVA_HOME/PATHfallback, no override setting.JAVA_TOOL_OPTIONS,_JAVA_OPTIONSandJDK_JAVA_OPTIONSare stripped from the server'senvironment — bundling a runtime and then letting the machine inject agents into
it defeats the point.
aadl2-<target>-<version>.vsix) for darwin-x64,darwin-arm64, linux-x64, linux-arm64, win32-x64 and win32-arm64. A bundled
runtime cannot be universal.
vsce.package.targetsselects the set:hostbydefault,
allfor a release.scripts/lib/temurin.sh, used by both bundlingpaths. It adds checksum verification against Adoptium's published digest, which
the osate-cli path never had.
failure, so a package installed for the wrong platform says so instead of
appearing as a generic activation error.
runtime, declared target platform, pre-release marker — before publishing
anything, and publishes them in a single
vsce publish. Marketplace versions areimmutable, so a partial publish would strand platforms on different versions.
Trade-offs
fallback is published. Documented in the README, CHANGELOG and RELEASING.
Verified locally
./scripts/build-test-release --skip-osate --skip-cligreen, with 29integration tests passing on the bundled JVM under
--disable-extensions—that suite previously skipped in its entirety.
darwin-x64is Mach-Ox86_64,
win32-*getjava.exe.code --install-extensioninto a clean profile:runtime/bin/javaandlib/jspawnhelperkeep mode 755 and the JRE runs, so nothing relies on achmod at startup.
and fails correctly on a missing target and on a pre-release mismatch.
Two traps worth knowing, both documented in the code:
maven-cleanfollows theruntimesymlink and deletes the cached JRE even withfollowSymlinks=false, andunzip -l | grep -qfails underpipefailbecause the SIGPIPE killsunzip.🤖 Generated with Claude Code