Repository navigation
Gradle Extension
This section describes the JDTLS importer in microsoft/vscode-gradle/extension/jdtls.ext/com.microsoft.gradle.bs.importer, not the task server or the separate Gradle Build Server. Evidence is pinned to source commit d2fad8a1d5b1096ea89ce7971e1b567482c6071f, merged by PR #1951 for issue #1949. The PR does not change the legacy task-server compatibility check, and its changelog entry is under Unreleased, not evidence of deployment.
GradleBuildServerBuildSupport.getHighestCompatibleJavaVersion supplies these new fallback upper bounds, choosing the highest matching Gradle threshold:
| Gradle threshold | Java upper bound |
|---|---|
| 8.10 | 23 |
| 8.14 | 24 |
| 9.1.0 | 25 |
| 9.4.0 | 26 |
| 9.8.0 | 27 |
At this revision, 9.8.1 maps to 27; older mappings remain, including 8.8 to 22. These are importer selection bounds at the cited revision, not a guarantee about future Gradle releases or a cap on project source levels.
setProjectJdk reads the BSP JVM target's source/target compatibility, writes the JDT compiler source, target, and compliance options, and passes target compatibility as the expected VM version and source compatibility as the fallback lower bound. EclipseVmUtil.getCompatibleVMWithHighestVersion prefers a valid exact target-version match before applying fallback bounds, even when that match exceeds the upper bound. Otherwise it selects the highest valid VM within the bounds from the execution environment's compatible VMs. Missing installations, embedded Java-extension JREs, and unknown Java versions are excluded. If no registered VM is found, findOrRegisterStandardVM registers the supplied Gradle daemon Java home. The compatibility matrix does not rewrite project source/target levels. These behaviors are verified in the linked source at the section's full commit SHA and retained by PR #1951.
GradleBuildServerBuildSupportTest contains 11 tests covering release/prerelease/patch boundaries, older mappings, exact-version preference, fallback bounds, invalid runtimes, and source/target preservation. Modeled Java 27 cases include a Java 25 service runtime with a Java 27 target, a Java 27 daemon, and an exact Java 27 match above the Gradle 9.1.0 fallback bound. These use mocked BSP targets and VM registrations; they are not live JDK 27 end-to-end imports. This maintenance review inspected tests but did not execute them.
The importer pom.xml configures test as the test source directory and Surefire 3.5.2, with explicit test-scoped BSP4J 2.1.0-M4, JUnit 4.13.2, and Mockito 5.20.0 dependencies. The explicit BSP4J test dependency is separate from the existing dependency-plugin artifact configuration.
CONTRIBUTING.md documents this PowerShell test entry point from the repository root (its development prerequisites list Java >= 21):
$env:MAVEN_OPTS = '-Djdk.xml.totalEntitySizeLimit=0 -Djdk.xml.maxGeneralEntitySizeLimit=0'
.\extension\jdtls.ext\mvnw.cmd -B -ntp -f .\extension\jdtls.ext\pom.xml -Declipse.p2.mirrors=false verifyAll validation sources above are from microsoft/vscode-gradle at d2fad8a1d5b1096ea89ce7971e1b567482c6071f (PR #1951); the development runtime prerequisite is distinct from imported project source/target compatibility.
The following configuration and live-test evidence is from microsoft/vscode-gradle at c0a51f482f9e5beefd8b6187581c4c7d0683c231, merged by PR #1953 for issue #1950. This adds live compatibility coverage alongside the importer unit tests above; it does not change the importer selection matrix. The changelog records the change under Unreleased.
-
Task Gradle distribution:
GradleProjectConnector.setConnectorConfigretains wrapper precedence. With the wrapper disabled, selection is explicitjava.import.gradle.version, configuredjava.import.gradle.home, systemGRADLE_HOME(environment, then Java system property), then fallback 9.8.1.build.gradle'stoolingAPIVersionalso changes from 9.2.0 to 9.8.1. This is a client/fallback update, not a forced upgrade of project wrappers. -
Keep JVM roles separate: the README settings guidance distinguishes Java language-server runtime (
java.jdt.ls.java.home), explicit Gradle daemon selection (java.import.gradle.java.home), and project toolchain (java.toolchain.languageVersionplus matchingjava.configuration.runtimes). Changing a toolchain alone does not change the daemon JVM. The task service is another process:getGradleServerEnvprefers the Java extension's embedded JRE, otherwisefindValidJavaHomechecks the Gradle-import Java home before JDTLS/legacy settings and environment discovery. Thus the task service need not use the language-server JVM. These selection functions are supporting context, not runtime-selection changes introduced by PR #1953.
GradleProjectConnectorTest adds five precedence/fallback tests. GradleToolingApiVersionTest.fallbackVersionMatchesResolvedToolingApiDependency checks the fallback constant against the resolved Tooling API package's implementation version; keep it synchronized with build.gradle.
The separate runCompatibilityTests.ts runner requires both JDK25_HOME and JDK27_HOME. It sets the Java language server to JDK 25 and the project runtime to JDK 27 in both scenarios:
| Scenario | Distribution | Task-service / daemon JVM | Project toolchain |
|---|---|---|---|
GRADLE_COMPATIBILITY_DAEMON=27 |
Wrapper disabled; 9.8.1 fallback; inherited GRADLE_HOME removed |
27 | 27 |
GRADLE_COMPATIBILITY_DAEMON=25 |
9.8.1 wrapper | 25 | 27 |
The runner uses isolated VS Code user/extension directories, Java extension 1.56.0's universal VSIX without an embedded JRE, and Java debugger 0.59.0. Its gradle-java27 fixture specifies a Java 27 toolchain and JUnit 4.13.2, without replacing the older fixtures. The six live integration tests assert task discovery and daemon version, BSP import with Java 27 source/target/runtime, dependency-model retrieval, JavaExec/JUnit execution, and real JavaExec/Test breakpoint stops. Debug checks inspect the source frame, evaluate feature as 27, continue, and require successful task completion. They explicitly pass an empty argument string to gradle.debugTask; they do not validate the command's omitted-argument path.
CONTRIBUTING.md directs developers to build importer, BSP server, task server, and extension using JDK 21, then run node out/test/runCompatibilityTests.js from extension (prefix with xvfb-run -a on headless Linux). Without GRADLE_COMPATIBILITY_DAEMON, both scenarios run. The runner stops daemons only in its scenario-specific Gradle user home and retains failed workspaces under extension/.vscode-test for diagnosis. .github/workflows/main.yml's test-java27-compatibility adds Ubuntu daemon-25/27 jobs alongside existing jobs and includes extension/server in the shared build artifact.
All sources in these two sections are pinned to c0a51f482f9e5beefd8b6187581c4c7d0683c231 (PR #1953). Maintenance inspected source and assertions, not executed tests or remote CI results. These are configured validation scenarios, not a blanket compatibility guarantee or proof of release/deployment.
Evidence: microsoft/vscode-gradle at merged source commit 26d8cb0519fc2ee3e085e0af0246d2e2c630b419, PR #1960, addressing issue #1948. Source identity: microsoft/vscode-gradle#1960:26d8cb0519fc2ee3e085e0af0246d2e2c630b419. This concerns the JDTLS Gradle/BSP importer adapter, not the task service or a change to debugger/JDTLS core implementations.
BuildServerBuilder.build and refreshOutputs wait for buildTargetCompile, reject BSP StatusCode.ERROR, then synchronously refresh output resources before the builder returns. Gradle can compile dependent projects without invoking their Eclipse builders; refreshing only the application outputs can therefore omit dependency class-file changes from the workspace build delta used for hot code replace. The PR expands workspace synchronization, not the compile request's target list or the debugger protocol.
- Traverse raw-classpath
CPE_PROJECTentries recursively, resolving workspace projects by the dependency path's last segment. Only accessible Gradle build-server dependencies are followed; inaccessible projects and projects without a Java model are skipped. - A per-invocation visited-project set deduplicates shared dependencies and terminates cycles. This is a conservative dependency refresh closure, not evidence that every visited project was recompiled.
- Preserve explicit per-source output refreshes at infinite depth. When a source entry uses the default output, refresh that default folder if it exists. Refresh
CoreExceptions propagate instead of reporting successful synchronization.
For the issue #1948 symptom—dependency bytecode changes on disk but the running JVM retains old behavior after HCR—inspect the importer's dependency-output synchronization boundary, rather than assuming Gradle did not compile or that a debugger change is required. PR #1960 supplies the importer-side remedy at the cited source revision; merge alone does not establish an installed extension version or deployment.
BuildServerBuilderTest adds four mocked regression tests for transitive/separate-source outputs, shared dependencies and cycles, closed/non-Gradle/non-Java dependencies, and propagation of dependency refresh failures. They invoke refreshOutputs directly; they do not exercise a real JVM HCR session or assert Eclipse POST_BUILD events. The existing importer Maven verification entry point above applies. Maintenance inspected both complete PR file patches and both final files at the full merged SHA, and did not execute tests. The PR reports a separate local app/lib live HCR comparison; its capture harness is not part of the product diff and is not evidence of automated CI HCR coverage.
Evidence: microsoft/vscode-gradle at merged source/source-tip commit 601eeb54467b44d4a263ecfb6af3ddfa41de7c85, PR #1961, addressing issue #1940. Source identity: microsoft/vscode-gradle#1961:601eeb54467b44d4a263ecfb6af3ddfa41de7c85. This changes the extension runner and its JDTLS importer delegate, not the separate BSP server implementation or debugger protocol. Merge does not establish release or deployment.
-
GradleTestRunner.launchWithBspcreates a unique temporary init script for BSP debugging, registers its path inbspInitScriptsbefore submission, and supplies the path as the optional sixth argument ofjava.gradle.delegateTest(after project, tests, Gradle args, VM args, and environment). Command return means asynchronous submission, not test completion; debugger attachment still starts without waiting for the BSP response. Test-report/finishTestRunevents do not release the script. -
GradleDelegateCommandHandler.executeCommand/notifyTestRequestCompleteobserves thebuildTargetTestfuture and sendsjava.gradle.buildServer.onDidCompleteTestRequestwith that exact path. Normal responses (including error/cancelled status), remoteResponseErrorException, and exceptions before a request is submitted permit notification. Callers omitting the path receive no script notification. -
BuildServerController's completion command forwards toGradleTestRunner.completeBspTestRequest. The runner removes only a registered path from its ownership set before deleting the file, making duplicate/unowned notifications harmless and allowing overlapping launches and completion before command return. Deletion failure logsFailed to delete Gradle test init script:; it does not reject completion or automatically retry.
The missing generated initialization-script symptom in BSP debugging can arise from deleting a script on submission return before Gradle consumes it; PR #1961 replaces that cleanup boundary with correlated request completion. The importer logs BSP test completion was not confirmed; retaining init script on connection loss, local future cancellation, or other non-remote-response failures, because those do not prove Gradle stopped using the file. The extension likewise retains the script on ambiguous command failure. Recognized unavailable-delegate errors release the BSP script before the existing XML fallback; launchXmlFallback retains its own per-launch cleanup in finally after runBuild. These behaviors are verified in the runner and handler sources linked above; this is not a guarantee that every ordinary Run/Test Explorer error shares the debugging cause.
GradleDelegateCommandHandlerTest adds nine mocked tests for asynchronous submission, remote failure, confirmed cancellation, transport/local-cancellation retention, pre-submission failure, already-completed requests, omitted paths, and overlapping requests. GradleTestRunner.test.ts adds six stubbed regression cases for lifetime through reporting, ownership/duplicates, early completion, ambiguous failure, unavailable-delegate fallback, and cleanup warnings, plus XML cleanup assertions. Maintenance inspected all six PR patches, rechecked stable PR metadata, and verified the three implementation files and both tests at the full merged/source-tip SHA; it did not execute tests. The PR reports separate live Windows BSP debugging validation, but not reproduction of the reporter's full macOS/Test Explorer scenario; its live harness is not part of these automated regression files.
At source commit 1ac4b9733133abc1ef9c31ea09c7b562c3e8800e, PR #1958 restores target-scoped App-token wiring in microsoft/vscode-gradle/.github/workflows/team-memory-post-merge.yml, jobs.team-memory.steps. This is repository automation, not Gradle runtime behavior. Source identity: microsoft/vscode-gradle#1958:1ac4b9733133abc1ef9c31ea09c7b562c3e8800e.
-
Authentication change:
Get coordinator dispatch tokenusesactions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1(annotated v3.2.0), withvars.ISSUELENS_DISPATCH_APP_CLIENT_IDandsecrets.ISSUELENS_DISPATCH_APP_PRIVATE_KEY. Its inputs restrict the target to ownermicrosoft, repositoryvscode-java-pack, requesting Contents read and Actions write. The queue step receivessteps.dispatch-token.outputs.token, replacinggithub.token. PR #1958 also removes source-jobcontents: read/actions: write; top-levelpermissions: {}remains. These dispatch permissions are not wiki Contents-write permissions. -
Retained dispatch contract: the queue action remains pinned to
microsoft/IssueLens/.github/actions/queue-team-memory@a81d2d96167fc0e69ac631c2edc85f858e693289, targetingmicrosoft/vscode-java-pack/team-memory-coordinator.yml/main. Its five string inputs aresource_repository,source_run_id,source_run_attempt,push_before(eventbefore), andpush_after(github.sha). -
Retained gates and lifecycle:
Queue IssueLens Team Memorytriggers on pushes todevelop.jobs.team-memory.ifrequires opt-inISSUELENS_TEAM_MEMORY_ENABLED == 'true', canonical repositorymicrosoft/vscode-gradle, the current default-branch ref, a push event, matching workflow/event SHA, and falsecreated,deleted, andforcedflags. It runs onubuntu-latestwith a 10-minute timeout. This source snapshot has no manual-dispatch trigger, checkout, or concurrency declaration; the historical direct-agent workflow below is not the current entry point. See Java Pack for separately sourced coordinator knowledge.
All current caller details above were verified in the linked workflow at the full source SHA, which is also the supplied push-after/source-tip revision. The complete one-file PR patch changes authentication only; retained gates and dispatch wiring are context, not features introduced by #1958. Maintenance inspected source and rechecked PR identities after paging; it did not execute tests, mint a dispatch token, or validate a live Gradle dispatch. Referenced configuration names do not establish that values or App installation permissions are configured, and this merge does not establish deployment or end-to-end delivery. External action internals and coordinator implementation were not revalidated.
The following retained account describes the older PR #1943 snapshot only; its manual recovery, permissions, action, concurrency, and timeout must not be applied to the current dispatcher above.
The following describes the caller workflow in microsoft/vscode-gradle, not Gradle task execution, language services, or the separate Gradle Build Server. Evidence: .github/workflows/team-memory-post-merge.yml, especially on, concurrency, and jobs.team-memory, at source commit 7dc995fc0fc1d705244e3db738ad423862134159 (PR #1943).
-
Automatic entry point: pushes to
develop; this replaces the closed-PRpull_request_targettrigger. The job additionally requiresISSUELENS_TEAM_MEMORY_ENABLED == 'true', the current default-branch ref, and either a push or manual-dispatch event. The push branch filter is literaldevelop, while the job's ref check uses repository default-branch metadata; a default-branch rename therefore requires reviewing the filter. -
Manual recovery: dispatch Update IssueLens Team Memory on the default branch with the required string input
pull_request_number, described as a merged PR number. The workflow passes that input to the action aspull-request-number; manual dispatch does not bypass the opt-in or branch gate. -
Concurrency and timeout: the group is
issuelens-${{ github.repository }}-team-memory-${{ github.event.after || inputs.pull_request_number || github.run_id }}. Pushes are keyed by their after-SHA, manual requests by PR number, with run ID as fallback. In-progress cancellation is disabled. The job runs onubuntu-latestwith a 30-minute timeout. -
Action boundary and permissions: the sole step invokes
microsoft/IssueLens/.github/actions/issuelens@2b5317815e15179899014a02c41678620ce2d390withrequest-type: team-memory,output-mode: activity, andsummary-mode: status. There is no checkout step. Workflow-level permissions are empty; job permissions arecontents: read,pull-requests: read, andid-token: write.
The caller source establishes these triggers, gates, inputs, and permissions, not the external action's internal PR-selection or batching implementation. Source inspection does not establish that opt-in variables, Azure federation, credentials, destination App permissions, or a live workflow run are correctly configured. PR #1943 changes only this workflow; it does not establish a Gradle feature release or deployment.
Evidence: microsoft/vscode-gradle at full merged/push-after/source-tip commit a1c997dd66db1d570eb499b21e8c45be87877b98, PR #1874, related to issue #1587. Source identity: microsoft/vscode-gradle#1874:a1c997dd66db1d570eb499b21e8c45be87877b98. This changes the extension's JDTLS importer and its validation, not the separate Gradle Build Server's BSP implementation, task transport, or Java language service. Merge does not establish release or deployment.
GradleBuildServerProjectImporter.applies, hasMultipleGradleRoots, and reset replace rejection based solely on workspace-root count with detection of Gradle-bearing roots:
- With Gradle import enabled and
java.gradle.buildServer.enabledset toon, adding plain workspace folders no longer disqualifies the Gradle root. A root without detected Gradle files still fails its own applicability check; at most one detected Gradle-bearing workspace root is allowed, not arbitrary independent Gradle builds. - For multiple workspace roots, scan each using
BasicFileDetectorforbuild.gradle,build.gradle.kts,settings.gradle, andsettings.gradle.kts, withincludeNested(false)and**/build/**/binexclusions. Count roots with nonempty scan results and stop once the count exceeds one. This counts workspace roots, not subprojects within one multi-project build. - More than one detected Gradle-bearing root still rejects the BSP importer. The
hasMultipleGradleRoots=truefallback telemetry is guarded by a staticAtomicBooleanacross importer instances, at most once per session.Utils.sendTelemetrynow ignores a null client; setting the guard does not prove notification delivery. - Existing checks for Buildship-imported Java projects, Android manifests, and root inference remain. A single Gradle-bearing root is therefore eligibility, not a guarantee of successful BSP import or automatic migration from Buildship. The configuration-selected
applies(Collection<IPath>, ...)overload remains disabled. -
reset()clears cacheddirectoriesand restoresisResolved=truewhen an importer instance switches roots. This prevents stale scans or prior unresolved state from affecting the next root, including the unresolved-state cleanup path that otherwise removes imported BSP projects from the workspace.
For multi-root fallback diagnosis (issue #1587), distinguish extra plain folders from extra Gradle-bearing roots and inspect existing importer gates. The PR reports a fresh-import app/subproject case with missing build/libs/*.jar errors resolved after this change; that report is not a source-backed guarantee for every missing-library diagnostic, and no downgrade or released-version remedy is established here.
GradleBuildServerProjectImporterTest adds four JUnit tests using temporary Gradle/plain folders and Eclipse workspace resources: plain-to-Gradle applicability, Gradle-to-plain non-applicability, rejection when both roots contain Gradle builds, and clearing unresolved state without deleting an already imported BSP project. Tests deliberately reuse one importer to exercise the defensive reset. They do not start a live BSP/Gradle build, validate subproject classpaths end to end, or assert telemetry deduplication.
The separate com.microsoft.gradle.bs.importer.test fragment uses src/ and bin/, hosts on com.microsoft.gradle.bs.importer, requires JavaSE-21 and org.junit, and packages as eclipse-test-plugin. Its pom.xml configures Tycho Surefire without a UI harness and with -Dsyntaxserver=true; the syntax-server setting is test-launch configuration, not product server mode. The target platform includes org.junit, and the parent Maven reactor includes the new test module alongside the existing importer module. This complements, rather than replaces, the importer tests documented above.
extension/build.gradle, buildJdtlsPlugin now invokes the Maven wrapper with clean verify instead of clean package to include the Tycho test phase. It retains the XML-limit MAVEN_OPTS, -Declipse.p2.mirrors=false, and optional MAVEN_REPO_LOCAL handling. The existing Maven verify entry point above therefore also includes the new reactor module. All nine PR patches were inspected sequentially, stable base/head/merge identities rechecked, and all nine final files read at the full source SHA above (push-after and source-tip are identical). Maintenance inspected configuration and assertions; it did not execute tests or verify remote CI passes. No batch dependency or superseding removal was found in this final-source/wiki comparison; unrelated knowledge remains pinned to its own cited revisions.