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.