Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/skills/uitest/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,6 @@ The repository workflow `.github/workflows/e2e-autotest.yml` builds a branch VSI

Use workflow dispatch when the user asks to validate in CI or across platforms. The `test_plan` input can target a single plan; leave it empty to run all plans.

For `java-gradle`, `java-gradle-java25`, and `java-gradle-java27`, CI uses one Gradle setup and the existing environment-binding mechanism. Java 21/25 helpers read `GRADLE_CI_GRADLE`, their `JAVA21_HOME`/`JAVA25_HOME`, and `AUTOTEST_STAGING_DIR`; the Java 27 helper retains its `JAVA27_CI_GRADLE` contract. CI does not rewrite terminal commands or override the IDE's Gradle home. Actual version, program-output and bytecode assertions remain unchanged. Local helper invocations retain their existing behavior.

For Java 21/25, the same binding exports `ORG_GRADLE_PROJECT_javaRelease` before VS Code starts. Local runs must set that project property as documented in the fixture README. These plans require BSP import, actual Gradle `build`/`run` tasks, and the exact configuration marker in Gradle for Java output; terminal success alone is insufficient. All three Gradle plans reuse the shared artifact collector: terminal diagnostics are staged outside AutoTest's output and archived under `diagnostics/ci/terminal/`, while Gradle/Java output-channel and extension-host logs are archived under `logs/ide/logs/`.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ jobs:

- run: npm ci

- run: npm test

- run: npm run build
62 changes: 42 additions & 20 deletions .github/workflows/e2e-autotest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,6 @@ jobs:
"JAVA27_HOME=$target" >> $env:GITHUB_ENV
Write-Host "Java 27 project toolchain: $target"

- name: Setup Gradle for Java 27
if: contains(matrix.plan, 'java27') && contains(matrix.plan, 'gradle')
uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0
with:
gradle-version: '9.8.1'

- name: Setup Java 25 (for java25 test plans)
if: contains(matrix.plan, 'java25')
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
Expand All @@ -196,6 +190,7 @@ jobs:
if: contains(matrix.plan, 'java25')
shell: pwsh
run: |
"JAVA25_HOME=$env:JAVA_HOME" >> $env:GITHUB_ENV
$planFile = "test-plans/${{ matrix.plan }}.yaml"
if ($IsWindows) {
$target = "C:\Program Files\Java\jdk-25"
Expand All @@ -219,22 +214,49 @@ jobs:
distribution: temurin
java-version: 21

- name: Bind Gradle Java 27 toolchain
if: matrix.plan == 'java-gradle-java27'
- name: Configure JDK 21 for Gradle import tests
if: matrix.plan == 'java-gradle' || matrix.plan == 'java-gradle-java25'
shell: pwsh
run: |
"JAVA21_HOME=$env:JAVA_HOME" >> $env:GITHUB_ENV
if ("${{ matrix.plan }}" -eq "java-gradle") {
$planFile = "test-plans/${{ matrix.plan }}.yaml"
# JSON escaping also handles Windows installation paths in double-quoted YAML.
$jdkPath = ($env:JAVA_HOME | ConvertTo-Json -Compress).Trim('"')
(Get-Content $planFile -Raw).Replace('C:\\Program Files\\Java\\jdk-21', $jdkPath) | Set-Content $planFile
}

- name: Setup Gradle for import tests
if: matrix.plan == 'java-gradle' || matrix.plan == 'java-gradle-java25' || matrix.plan == 'java-gradle-java27'
uses: gradle/actions/setup-gradle@3f5f9adaf7d9fecd50b5935e54106014257a94e6 # v6.4.0
with:
gradle-version: ${{ matrix.plan == 'java-gradle' && '8.5' || '9.8.1' }}

- name: Bind Gradle for import tests
if: matrix.plan == 'java-gradle' || matrix.plan == 'java-gradle-java25' || matrix.plan == 'java-gradle-java27'
shell: pwsh
env:
GRADLE_TEST_PLAN: ${{ matrix.plan }}
run: |
$ciGradle = (Get-Command gradle -CommandType Application -ErrorAction Stop | Select-Object -First 1).Source
$versionLog = Join-Path $env:AUTOTEST_STAGING_DIR "gradle-version.log"
$PSNativeCommandUseErrorActionPreference = $false
$gradleVersion = & $ciGradle --version 2>&1 | Out-String
$versionExit = $LASTEXITCODE
"Command: $ciGradle --version`n$gradleVersion" | Set-Content -LiteralPath $versionLog
if ($versionExit -ne 0) { throw "CI Gradle version probe exited with $versionExit; see diagnostics/ci/gradle-version.log in this case's results artifact." }
if ($gradleVersion -notmatch '(?m)^Gradle 9\.8\.1\s*$') {
throw "CI did not select the provisioned Gradle 9.8.1: $ciGradle; see $versionLog"
$release = if ($env:GRADLE_TEST_PLAN -eq "java-gradle") { "21" } elseif ($env:GRADLE_TEST_PLAN -eq "java-gradle-java25") { "25" } else { "27" }
if ($release -eq "27") {
$versionLog = Join-Path $env:AUTOTEST_STAGING_DIR "gradle-version.log"
$PSNativeCommandUseErrorActionPreference = $false
$gradleVersion = & $ciGradle --version 2>&1 | Out-String
$versionExit = $LASTEXITCODE
"Command: $ciGradle --version`n$gradleVersion" | Set-Content -LiteralPath $versionLog
if ($versionExit -ne 0) { throw "CI Gradle version probe exited with $versionExit; see diagnostics/ci/gradle-version.log in this case's results artifact." }
if ($gradleVersion -notmatch '(?m)^Gradle 9\.8\.1\s*$') {
throw "CI did not select the provisioned Gradle 9.8.1: $ciGradle; see $versionLog"
}
"JAVA27_CI_GRADLE=$ciGradle" >> $env:GITHUB_ENV
} else {
"ORG_GRADLE_PROJECT_javaRelease=$release" >> $env:GITHUB_ENV
}
"JAVA27_CI_GRADLE=$ciGradle" >> $env:GITHUB_ENV
Write-Host "Bound Gradle 9.8.1: $ciGradle"
"GRADLE_CI_GRADLE=$ciGradle" >> $env:GITHUB_ENV
"GRADLE_CI_JAVA_HOME=$([Environment]::GetEnvironmentVariable("JAVA${release}_HOME"))" >> $env:GITHUB_ENV
Write-Host "Bound CI Gradle: $ciGradle"

- name: Setup virtual display (Linux)
if: runner.os == 'Linux'
Expand Down Expand Up @@ -429,8 +451,8 @@ jobs:
run: |
$identity = [ordered]@{
javaHome = $env:JAVA_HOME
projectJavaHome = $env:JAVA27_HOME
gradle = $env:JAVA27_CI_GRADLE
projectJavaHome = $(if ($env:GRADLE_CI_JAVA_HOME) { $env:GRADLE_CI_JAVA_HOME } else { $env:JAVA27_HOME })
gradle = $env:GRADLE_CI_GRADLE
runnerOs = $env:RUNNER_OS
runnerArch = $env:RUNNER_ARCH
path = $env:PATH
Expand Down
1 change: 1 addition & 0 deletions .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ scripts
test-fixtures/**
test-plans/**
test-results/**
tests/**
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ At the same time, [📦 CheckStyle](https://marketplace.visualstudio.com/items?i

## Questions & Issues

See the [Java runtime requirements and configuration](https://github.com/microsoft/vscode-java-pack/wiki/Java-Runtime-Requirements) guide for JDK setup details.

Each extension mentioned above is a separate open-source project and has its own repository. To make things easier, simply [🙋 open an issue in this repository](https://github.com/Microsoft/vscode-java-pack/issues). The new issue will be triaged and redirected.

## Data/Telemetry
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,7 @@
"compile": "webpack --config webpack.config.js",
"watch": "webpack --config webpack.config.js --watch",
"build": "webpack --config webpack.config.js --mode=\"production\"",
"test": "node --test",
Comment thread
wenytang-ms marked this conversation as resolved.
"update-tpn": "node scripts/update-third-party-notice.js"
},
"devDependencies": {
Expand Down
4 changes: 2 additions & 2 deletions src/beginner-tips/assets/BeginnerTips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import DebuggingPanel from "./tabs/DebuggingPanel";
import FaqPanel from "./tabs/FaqPanel";
import QuickStartPanel from "./tabs/QuickStartPanel";

export default function BeginnerTips() {
export default function BeginnerTips({ requiredJdkVersion }: { requiredJdkVersion: number }) {

return (
<div className="container mt-5 mb-5">
Expand All @@ -33,7 +33,7 @@ export default function BeginnerTips() {
<DebuggingPanel />
</vscode-tab-panel>
<vscode-tab-panel>
<FaqPanel />
<FaqPanel requiredJdkVersion={requiredJdkVersion} />
</vscode-tab-panel>
</vscode-tabs>
</div>
Expand Down
5 changes: 3 additions & 2 deletions src/beginner-tips/assets/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
import { createRoot } from 'react-dom/client';
import BeginnerTips from "./BeginnerTips";

const root = createRoot(document.getElementById('root')!);
root.render(<BeginnerTips />);
const container = document.getElementById('root')!;
const root = createRoot(container);
root.render(<BeginnerTips requiredJdkVersion={Number(container.dataset.requiredJdkVersion)} />);
12 changes: 8 additions & 4 deletions src/beginner-tips/assets/tabs/FaqPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import "@vscode-elements/elements/dist/vscode-table/index.js";
import "@vscode-elements/elements/dist/vscode-table-row/index.js";
import "@vscode-elements/elements/dist/vscode-table-cell/index.js";
import "@vscode-elements/elements/dist/vscode-table-body/index.js";
const REQUIRED_JDK_VERSION = 17;
import { encodeCommandUriWithTelemetry } from "../../../utils/webview";

export default function FaqPanel() {
export default function FaqPanel({ requiredJdkVersion }: { requiredJdkVersion: number }) {
const toolingSettingsCommand = encodeCommandUriWithTelemetry("java.gettingStarted", "toolingSettings", "workbench.action.openSettings", ["java.jdt.ls.java.home"]);
const runtimeSampleCode = (
<code>
<span>{"\"java.configuration.runtimes\": [{"}</span><br />
Expand Down Expand Up @@ -50,12 +51,15 @@ export default function FaqPanel() {

<h2 className="font-weight-light">Why do I see the JDK errors?</h2>
<p>
<strong><code>JDK {REQUIRED_JDK_VERSION}+</code> is required</strong> to run the Java language support (redhat.java) extension! You see this error because we failed to find one on your machine. The <a href="command:java.runtime">Configure Java Runtime</a> guide can help you understand how JDK path is searched and provides download links if you need to install one.
<strong><code>JDK {requiredJdkVersion}+</code> is required</strong> to run the installed Java language support (redhat.java) extension. A compatible bundled runtime can satisfy this requirement; otherwise, a compatible local JDK is needed. To set the language-server launch JDK explicitly, configure <a href={toolingSettingsCommand}><code>java.jdt.ls.java.home</code></a>. Runtime selection and startup diagnostics are provided by redhat.java; <a href="command:java.open.logs">open the Java logs</a> for details.
</p>
<p>
The <a href="command:java.runtime">Configure Java Runtime</a> page configures project JDKs, not the language-server launch JDK. Your projects can use older JDKs independently of the tooling requirement.
</p>

<h2 className="font-weight-light">Can I run my Java 8 project with JDK 1.8?</h2>
<p>
Yes. The JDK {REQUIRED_JDK_VERSION} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime <a href="command:java.helper.openUrl?%22https%3A%2F%2Fcode.visualstudio.com%2Fdocs%2Fjava%2Fjava-project%23_jdk-for-projects%22">JDK for your project</a> via the user setting <a href="command:workbench.action.openSettings?%22java.configuration.runtimes%22">"java.configuration.runtimes"</a>. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file.
Yes. The JDK {requiredJdkVersion} requirement is just for running the Java language support (redhat.java) extension itself. You can still configure a different runtime <a href="command:java.helper.openUrl?%22https%3A%2F%2Fcode.visualstudio.com%2Fdocs%2Fjava%2Fjava-project%23_jdk-for-projects%22">JDK for your project</a> via the user setting <a href="command:workbench.action.openSettings?%22java.configuration.runtimes%22">"java.configuration.runtimes"</a>. The extension will pick a matching JDK to compile/run your project according to the compiler version specified by the project build file.
</p>
<blockquote className="card-body">
{runtimeSampleCode}
Expand Down
3 changes: 2 additions & 1 deletion src/beginner-tips/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as path from "path";
import * as vscode from "vscode";
import { sendInfo } from "vscode-extension-telemetry-wrapper";
import { getNonce, webviewCmdLinkHandler } from "../utils";
import { getRequiredJdkVersion } from "../java-runtime/utils/upstreamApi";

const WEBVIEW_ID = "java.gettingStarted";
const WEBVIEW_TITLE = "Tips for Beginners";
Expand Down Expand Up @@ -122,7 +123,7 @@ class BeginnerTipsPage {
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="root" data-required-jdk-version="${getRequiredJdkVersion()}"></div>

<script nonce="${nonce}" src="${scriptUri}" type="module"></script>
</body>
Expand Down
8 changes: 1 addition & 7 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { JavaExtGuideViewSerializer } from "./ext-guide";
import { initFormatterSettingsEditorProvider } from "./formatter-settings";
import { initRemoteProfileProvider } from "./formatter-settings/RemoteProfileProvider";
import { InstallJdkViewSerializer } from "./install-jdk";
import { JavaRuntimeViewSerializer, validateJavaRuntime } from "./java-runtime";
import { JavaRuntimeViewSerializer } from "./java-runtime";
import { HelpViewType, showReleaseNotesOnStart } from "./misc";
import { OverviewViewSerializer } from "./overview";
import { CodeActionProvider } from "./providers/CodeActionProvider";
Expand Down Expand Up @@ -76,12 +76,6 @@ async function initializeExtension(_operationId: string, context: vscode.Extensi
showReleaseNotesOnStart(context);
});
}

if (!await validateJavaRuntime()) {
scheduleAction("showJdkState", true, true).then(() => {
vscode.commands.executeCommand("java.runtime");
});
}
}

async function presentFirstView(context: vscode.ExtensionContext) {
Expand Down
28 changes: 25 additions & 3 deletions src/java-runtime/assets/ProjectJDKPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,22 @@ import { useState } from "react";
import { encodeCommandUriWithTelemetry, ProjectType } from "../../utils/webview";
import { JavaRuntimeEntry, ProjectRuntimeEntry } from "../types";
import { DefaultJDKSelector } from "./components/DefaultJDKSelector";
import { JDKActions } from "./components/JDKActions";
import { ProjectTypeHint } from "./components/ProjectTypeHint";
import { onWillListRuntimes, openBuildScript } from "./vscode.api";

interface Props {
jdkEntries: JavaRuntimeEntry[];
projectRuntimes: ProjectRuntimeEntry[];
javaDotHome?: string;
toolingJreVersion?: number;
requiredJdkVersion: number;
javaHomeError?: string;
javaHomeWarning?: string;
projectJdkError?: string;
}

export function ProjectJDKPanel({ jdkEntries, projectRuntimes }: Props) {
export function ProjectJDKPanel({ jdkEntries, projectRuntimes, javaDotHome, toolingJreVersion, requiredJdkVersion, javaHomeError, javaHomeWarning, projectJdkError }: Props) {
const [showHintFor, setShowHintFor] = useState<"Maven" | "Gradle" | "Others" | undefined>();

const projectTypeHint = (projectType: ProjectType) => {
Expand Down Expand Up @@ -68,10 +75,21 @@ export function ProjectJDKPanel({ jdkEntries, projectRuntimes }: Props) {
));

const downloadJDKCommand = encodeCommandUriWithTelemetry("java.runtime", "download", "java.installJdk");
const toolingSettingsCommand = encodeCommandUriWithTelemetry("java.runtime", "toolingSettings", "workbench.action.openSettings", ["java.jdt.ls.java.home"]);

return (
<div className="container">
<h1>Configure Runtime for Projects</h1>
{javaDotHome ? (
<p>Language server runtime reported by redhat.java: <code>{javaDotHome}</code> (Java {toolingJreVersion}).</p>
) : (
<p>Language server runtime information is not available yet. Use Refresh after redhat.java starts, or <a href="command:java.open.logs">open the Java logs</a> for details.</p>
)}
<p>JDK {requiredJdkVersion}+ is required for the language server only; your projects can use older JDKs. <a href={toolingSettingsCommand}>Open language-server runtime settings</a>.</p>
{javaHomeError && <p className="java-home-error">{javaHomeError} <a href="command:java.open.logs">Open Java Logs</a>.</p>}
{javaHomeWarning && <p className="warning-box">{javaHomeWarning} <a href="command:java.open.logs">Open Java Logs</a>.</p>}
{projectJdkError && <p className="java-home-error">{projectJdkError} <a href="command:java.open.logs">Open Java Logs</a>.</p>}
{!javaDotHome && <JDKActions />}
{projectEntries.length > 0 && <p>Manage Java runtime for your projects. If you don't have a valid Java runtime, you can <a href={downloadJDKCommand}>download</a> one.</p>}
{
projectEntries.length > 0 ?
Expand All @@ -87,10 +105,14 @@ export function ProjectJDKPanel({ jdkEntries, projectRuntimes }: Props) {
</vscode-table>
:
<div>
<p>No project detected yet. Please refresh later if Java extension is importing your projects.</p>
<vscode-button onClick={onWillListRuntimes}>Refresh<span slot="start" className="codicon codicon-refresh"></span></vscode-button>
{projectJdkError ?
<p>Project information could not be fully loaded. Please refresh to try again.</p>
:
<p>No project detected yet. Please refresh later if Java extension is importing your projects.</p>
}
</div>
}
<vscode-button onClick={onWillListRuntimes}>Refresh<span slot="start" className="codicon codicon-refresh"></span></vscode-button>
<ProjectTypeHint projectType={showHintFor} />
</div>
);
Expand Down
Loading
Loading