diff --git a/.azure-pipelines/publish-to-maven.yml b/.azure-pipelines/publish-to-maven.yml
index 58dc58cf2..a1ef0a204 100644
--- a/.azure-pipelines/publish-to-maven.yml
+++ b/.azure-pipelines/publish-to-maven.yml
@@ -22,6 +22,10 @@ extends:
- stage: PublishToMaven
jobs:
- job: PublishToMaven
+ displayName: Maven Release job
+ templateContext:
+ type: releaseJob
+ isProduction: true
steps:
- task: DownloadBuildArtifacts@1
displayName: 'Download Jar Artifacts'
diff --git a/.azure-pipelines/signjars-nightly.yml b/.azure-pipelines/signjars-nightly.yml
index b2ab77ab7..8b1e8d12a 100644
--- a/.azure-pipelines/signjars-nightly.yml
+++ b/.azure-pipelines/signjars-nightly.yml
@@ -45,20 +45,23 @@ extends:
steps:
- checkout: self
fetchTags: true
- - task: UsePythonVersion@0
- displayName: 'Use Python 3.11.x'
- inputs:
- versionSpec: 3.11.x
- task: UseDotNet@2
displayName: 'Use .NET Core 3.1.x'
inputs:
packageType: 'sdk'
version: '3.1.x'
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core 8.0.x'
+ inputs:
+ packageType: 'sdk'
+ version: '8.0.x'
- task: MicroBuildSigningPlugin@4
displayName: 'Install Signing Plugin'
inputs:
signType: real
azureSubscription: 'MicroBuild Signing Task (MSEng)'
+ useEsrpCli: true
+ ConnectedPMEServiceName: 0e38ce24-f885-4c86-b997-5887b97a1899
feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
@@ -98,6 +101,8 @@ extends:
dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171
done
workingDirectory: 'jars'
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CmdLine@2
displayName: install signed core.jar
inputs:
@@ -122,6 +127,8 @@ extends:
dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171
done
workingDirectory: 'jars'
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CopyFiles@2
displayName: "Copy plugin.jar to: $(Build.ArtifactStagingDirectory)"
inputs:
diff --git a/.azure-pipelines/signjars-rc.yml b/.azure-pipelines/signjars-rc.yml
index 8e639bafb..e87444603 100644
--- a/.azure-pipelines/signjars-rc.yml
+++ b/.azure-pipelines/signjars-rc.yml
@@ -40,20 +40,23 @@ extends:
steps:
- checkout: self
fetchTags: true
- - task: UsePythonVersion@0
- displayName: 'Use Python 3.11.x'
- inputs:
- versionSpec: 3.11.x
- task: UseDotNet@2
displayName: 'Use .NET Core 3.1.x'
inputs:
packageType: 'sdk'
version: '3.1.x'
+ - task: UseDotNet@2
+ displayName: 'Use .NET Core 8.0.x'
+ inputs:
+ packageType: 'sdk'
+ version: '8.0.x'
- task: MicroBuildSigningPlugin@4
displayName: 'Install Signing Plugin'
inputs:
signType: real
azureSubscription: 'MicroBuild Signing Task (MSEng)'
+ useEsrpCli: true
+ ConnectedPMEServiceName: 0e38ce24-f885-4c86-b997-5887b97a1899
feedSource: 'https://mseng.pkgs.visualstudio.com/DefaultCollection/_packaging/MicroBuildToolset/nuget/v3/index.json'
env:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
@@ -95,6 +98,8 @@ extends:
dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171
done
workingDirectory: 'jars'
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CmdLine@2
displayName: install signed core.jar
inputs:
@@ -118,6 +123,8 @@ extends:
dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$fileName" /certs:100010171
done
workingDirectory: 'jars'
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CmdLine@2
displayName: install signed plugin.jar
inputs:
@@ -152,6 +159,8 @@ extends:
dotnet "$MBSIGN_APPFOLDER/DDSignFiles.dll" -- /file:"$file" /certs:100010171
done
workingDirectory: 'm2'
+ env:
+ SYSTEM_ACCESSTOKEN: $(System.AccessToken)
- task: CopyFiles@2
displayName: "Copy m2 to: $(Build.ArtifactStagingDirectory)"
inputs:
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index b11684f52..9d7579633 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -1 +1 @@
-* @testforstephen @jdneo
\ No newline at end of file
+* @testforstephen @jdneo @chagong @wenytang-ms
diff --git a/.github/llms.md b/.github/llms.md
new file mode 100644
index 000000000..55d69b238
--- /dev/null
+++ b/.github/llms.md
@@ -0,0 +1,38 @@
+# Extension Pack for Java
+Extension Pack for Java is a collection of popular extensions that can help write, test and debug Java applications in Visual Studio Code. By installing Extension Pack for Java, the following extensions are installed:
+
+- [📦 Language Support for Java™ by Red Hat ](https://marketplace.visualstudio.com/items?itemName=redhat.java)
+ - Code Navigation
+ - Auto Completion
+ - Refactoring
+ - Code Snippets
+- [📦 Debugger for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-debug)
+ - Debugging
+- [📦 Test Runner for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-test)
+ - Run & Debug JUnit/TestNG Test Cases
+- [📦 Maven for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-maven)
+ - Project Scaffolding
+ - Custom Goals
+- [📦 Gradle for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-gradle)
+ - View Gradle tasks and project dependencies
+ - Gradle file authoring
+ - Import Gradle projects via [Gradle Build Server](https://github.com/microsoft/build-server-for-gradle)
+- [📦 Project Manager for Java](https://marketplace.visualstudio.com/items?itemName=vscjava.vscode-java-dependency)
+ - Manage Java projects, referenced libraries, resource files, packages, classes, and class members
+- [📦 Visual Studio IntelliCode](https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode)
+ - AI-assisted development
+ - Completion list ranked by AI
+
+## Label
+When labeling an issue, follow the rules below per label category:
+### General Rules
+- Analyze if the issue is related with the scope of using extensions for Java development. If not, STOP labelling IMMEDIATELY.
+- Assign label per category.
+- If a category is not applicable or you're unsure, you may skip it.
+- Do not assign multiple labels within the same category, unless explicitly allowed as an exception.
+
+### Issue Type Labels
+- [bug]: Primary label for real bug issues
+- [enhancement]: Primary label for enhancement issues
+- [documentation]: Primary label for documentation issues
+- [question]: Primary label for question issues
\ No newline at end of file
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 71d726f63..553d95a9a 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -12,80 +12,83 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v5
- - name: Set up JDK 21
- uses: actions/setup-java@v1
- with:
- java-version: '21'
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
+ with:
+ java-version: '21'
+ distribution: 'temurin'
- - name: Cache local Maven repository
- uses: actions/cache@v4
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+ - name: Cache local Maven repository
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
- - name: Verify
- run: ./mvnw clean verify -U
+ - name: Verify
+ run: ./mvnw clean verify -U
- - name: Checkstyle
- run: ./mvnw checkstyle:check
+ - name: Checkstyle
+ run: ./mvnw checkstyle:check
windows:
name: Windows
runs-on: windows-latest
timeout-minutes: 30
steps:
- - name: Set git to use LF
- run: |
- git config --global core.autocrlf false
- git config --global core.eol lf
+ - name: Set git to use LF
+ run: |
+ git config --global core.autocrlf false
+ git config --global core.eol lf
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v5
- - name: Set up JDK 21
- uses: actions/setup-java@v1
- with:
- java-version: '21'
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
+ with:
+ java-version: '21'
+ distribution: 'temurin'
- - name: Cache local Maven repository
- uses: actions/cache@v4
- with:
- path: $HOME/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+ - name: Cache local Maven repository
+ uses: actions/cache@v4
+ with:
+ path: $HOME/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
- - name: Verify
- run: ./mvnw.cmd clean verify
+ - name: Verify
+ run: ./mvnw.cmd clean verify
- - name: Checkstyle
- run: ./mvnw.cmd checkstyle:check
+ - name: Checkstyle
+ run: ./mvnw.cmd checkstyle:check
darwin:
name: macOS
runs-on: macos-latest
timeout-minutes: 30
steps:
- - uses: actions/checkout@v2
-
- - name: Set up JDK 21
- uses: actions/setup-java@v1
- with:
- java-version: '21'
-
- - name: Cache local Maven repository
- uses: actions/cache@v4
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
-
- - name: Verify
- run: ./mvnw clean verify -U
-
- - name: Checkstyle
- run: ./mvnw checkstyle:check
+ - uses: actions/checkout@v5
+
+ - name: Set up JDK 21
+ uses: actions/setup-java@v5
+ with:
+ java-version: '21'
+ distribution: 'temurin'
+
+ - name: Cache local Maven repository
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ - name: Verify
+ run: ./mvnw clean verify -U
+
+ - name: Checkstyle
+ run: ./mvnw checkstyle:check
diff --git a/.github/workflows/triage-agent.yml b/.github/workflows/triage-agent.yml
new file mode 100644
index 000000000..f1df6e117
--- /dev/null
+++ b/.github/workflows/triage-agent.yml
@@ -0,0 +1,125 @@
+name: AI Triage
+on:
+ issues:
+ types: [opened]
+ workflow_dispatch:
+ inputs:
+ issue_number:
+ description: 'Issue number to triage (manual run). e.g. 123'
+ required: true
+
+run-name: >-
+ AI Triage for Issue #${{ github.event.issue.number || github.event.inputs.issue_number }}
+
+permissions:
+ issues: write
+ contents: read
+
+jobs:
+ label_and_comment:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ - name: Get issue data
+ id: get_issue
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const eventName = context.eventName;
+ let issue;
+ if (eventName === 'workflow_dispatch') {
+ const inputs = context.payload.inputs || {};
+ const issueNumber = inputs.issue_number || inputs.issueNumber;
+ if (!issueNumber) core.setFailed('Input issue_number is required for manual run.');
+ const { data } = await github.rest.issues.get({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: parseInt(issueNumber, 10),
+ });
+ issue = data;
+ } else if (context.payload.issue) {
+ issue = context.payload.issue;
+ } else {
+ core.setFailed('No issue information found in the event payload.');
+ }
+ core.setOutput('id', String(issue.number));
+ core.setOutput('user', String((issue.user && issue.user.login) || ''));
+ core.setOutput('title', String(issue.title || ''));
+ core.setOutput('body', String(issue.body || ''));
+ const labelNames = (issue.labels || []).map(label => label.name);
+ core.setOutput('labels', JSON.stringify(labelNames));
+
+ - name: Call Azure Function
+ id: call_azure_function
+ env:
+ PAYLOAD: >-
+ {
+ "authToken": "${{ secrets.GITHUB_TOKEN }}",
+ "repoId": "microsoft/java-debug",
+ "issueData": {
+ "id": ${{ steps.get_issue.outputs.id }},
+ "user": ${{ toJson(steps.get_issue.outputs.user) }},
+ "title": ${{ toJson(steps.get_issue.outputs.title) }},
+ "body": ${{ toJson(steps.get_issue.outputs.body) }},
+ "labels": ${{ steps.get_issue.outputs.labels }}
+ },
+ "mode": "DirectUpdate"
+ }
+
+ run: |
+ # Make the HTTP request with improved error handling and timeouts
+ echo "Making request to triage agent..."
+
+ # Add timeout handling and better error detection
+ set +e # Don't exit on curl failure
+ response=$(timeout ${{ vars.TRIAGE_AGENT_TIMEOUT }} curl \
+ --max-time 0 \
+ --connect-timeout 30 \
+ --fail-with-body \
+ --silent \
+ --show-error \
+ --write-out "HTTPSTATUS:%{http_code}" \
+ --header "Content-Type: application/json" \
+ --request POST \
+ --data "$PAYLOAD" \
+ ${{ secrets.TRIAGE_FUNCTION_LINK }} 2>&1)
+
+ curl_exit_code=$?
+ set -e # Re-enable exit on error
+
+ echo "Curl exit code: $curl_exit_code"
+
+ # Check if curl command timed out or failed
+ if [ $curl_exit_code -eq 124 ]; then
+ echo "❌ Request timed out after 650 seconds"
+ exit 1
+ elif [ $curl_exit_code -ne 0 ]; then
+ echo "❌ Curl command failed with exit code: $curl_exit_code"
+ echo "Response: $response"
+ exit 1
+ fi
+
+ # Extract HTTP status code and response body
+ http_code=$(echo "$response" | grep -o "HTTPSTATUS:[0-9]*" | cut -d: -f2)
+ response_body=$(echo "$response" | sed 's/HTTPSTATUS:[0-9]*$//')
+
+ echo "HTTP Status Code: $http_code"
+
+ # Validate HTTP status code
+ if [ -z "$http_code" ]; then
+ echo "❌ Failed to extract HTTP status code from response"
+ echo "Raw response: $response"
+ exit 1
+ fi
+
+ # Check if the request was successful
+ if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
+ echo "✅ Azure Function call succeeded"
+ else
+ echo "❌ Azure Function call failed with status code: $http_code"
+ echo "Response: $response_body"
+ exit 1
+ fi
\ No newline at end of file
diff --git a/.github/workflows/triage-all-open-issues.yml b/.github/workflows/triage-all-open-issues.yml
new file mode 100644
index 000000000..092f4ef70
--- /dev/null
+++ b/.github/workflows/triage-all-open-issues.yml
@@ -0,0 +1,145 @@
+name: AI Triage - Process All Open Issues
+on:
+ workflow_dispatch:
+ inputs:
+ dry_run:
+ description: 'Dry run mode - only list issues without processing'
+ required: false
+ default: false
+ type: boolean
+ max_issues:
+ description: 'Maximum number of issues to process (0 = all)'
+ required: false
+ default: '0'
+ type: string
+
+permissions:
+ issues: write
+ contents: read
+ actions: write
+
+jobs:
+ get_open_issues:
+ runs-on: ubuntu-latest
+ outputs:
+ issue_numbers: ${{ steps.get_issues.outputs.issue_numbers }}
+ total_count: ${{ steps.get_issues.outputs.total_count }}
+
+ steps:
+ - name: Get all open issues
+ id: get_issues
+ uses: actions/github-script@v6
+ with:
+ script: |
+ // Use Search API to filter issues at API level
+ const { data } = await github.rest.search.issuesAndPullRequests({
+ q: `repo:${context.repo.owner}/${context.repo.repo} is:issue is:open -label:ai-triaged -label:invalid`,
+ sort: 'created',
+ order: 'asc',
+ per_page: 100
+ });
+
+ const actualIssues = data.items;
+
+ let issuesToProcess = actualIssues;
+ const maxIssues = parseInt('${{ inputs.max_issues }}' || '0');
+
+ if (maxIssues > 0 && actualIssues.length > maxIssues) {
+ issuesToProcess = actualIssues.slice(0, maxIssues);
+ console.log(`Limiting to first ${maxIssues} issues out of ${actualIssues.length} total`);
+ }
+
+ const issueNumbers = issuesToProcess.map(issue => issue.number);
+ const totalCount = issuesToProcess.length;
+
+ console.log(`Found ${actualIssues.length} open issues, processing ${totalCount}:`);
+ issuesToProcess.forEach(issue => {
+ console.log(` #${issue.number}: ${issue.title}`);
+ });
+
+ core.setOutput('issue_numbers', JSON.stringify(issueNumbers));
+ core.setOutput('total_count', totalCount);
+
+ process_issues:
+ runs-on: ubuntu-latest
+ needs: get_open_issues
+ if: needs.get_open_issues.outputs.total_count > 0
+
+ strategy:
+ # Process issues one by one (max-parallel: 1)
+ max-parallel: 1
+ matrix:
+ issue_number: ${{ fromJSON(needs.get_open_issues.outputs.issue_numbers) }}
+
+ steps:
+ - name: Log current issue being processed
+ run: |
+ echo "🔄 Processing issue #${{ matrix.issue_number }}"
+ echo "Total issues to process: ${{ needs.get_open_issues.outputs.total_count }}"
+
+ - name: Check if dry run mode
+ if: inputs.dry_run == true
+ run: |
+ echo "🔍 DRY RUN MODE: Would process issue #${{ matrix.issue_number }}"
+ echo "Skipping actual triage processing"
+
+ - name: Trigger triage workflow for issue
+ if: inputs.dry_run != true
+ uses: actions/github-script@v6
+ with:
+ script: |
+ const issueNumber = '${{ matrix.issue_number }}';
+
+ try {
+ console.log(`Triggering triage workflow for issue #${issueNumber}`);
+
+ const response = await github.rest.actions.createWorkflowDispatch({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ workflow_id: 'triage-agent.yml',
+ ref: 'main',
+ inputs: {
+ issue_number: issueNumber
+ }
+ });
+
+ console.log(`✅ Successfully triggered triage workflow for issue #${issueNumber}`);
+
+ } catch (error) {
+ console.error(`❌ Failed to trigger triage workflow for issue #${issueNumber}:`, error);
+ core.setFailed(`Failed to process issue #${issueNumber}: ${error.message}`);
+ }
+
+ - name: Wait for workflow completion
+ if: inputs.dry_run != true
+ run: |
+ echo "⏳ Waiting for triage workflow to complete for issue #${{ matrix.issue_number }}..."
+ echo "Timeout: ${{ vars.TRIAGE_AGENT_TIMEOUT }} seconds"
+ sleep ${{ vars.TRIAGE_AGENT_TIMEOUT }} # Wait for triage workflow completion
+
+ summary:
+ runs-on: ubuntu-latest
+ needs: [get_open_issues, process_issues]
+ if: always()
+
+ steps:
+ - name: Print summary
+ run: |
+ echo "## Triage Processing Summary"
+ echo "Total open issues found: ${{ needs.get_open_issues.outputs.total_count }}"
+
+ if [ "${{ inputs.dry_run }}" == "true" ]; then
+ echo "Mode: DRY RUN (no actual processing performed)"
+ else
+ echo "Mode: FULL PROCESSING"
+ fi
+
+ if [ "${{ needs.process_issues.result }}" == "success" ]; then
+ echo "✅ All issues processed successfully"
+ elif [ "${{ needs.process_issues.result }}" == "failure" ]; then
+ echo "❌ Some issues failed to process"
+ elif [ "${{ needs.process_issues.result }}" == "skipped" ]; then
+ echo "⏭️ Processing was skipped (no open issues found)"
+ else
+ echo "⚠️ Processing completed with status: ${{ needs.process_issues.result }}"
+ fi
diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar
deleted file mode 100644
index 41c70a7e0..000000000
Binary files a/.mvn/wrapper/maven-wrapper.jar and /dev/null differ
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index 9e0264d04..44f3cf2c1 100644
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1 +1,2 @@
-distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.3/apache-maven-3.9.3-bin.zip
\ No newline at end of file
+distributionType=only-script
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
diff --git a/com.microsoft.java.debug.core/.classpath b/com.microsoft.java.debug.core/.classpath
index 9ba41a249..b6fe6b96c 100644
--- a/com.microsoft.java.debug.core/.classpath
+++ b/com.microsoft.java.debug.core/.classpath
@@ -13,7 +13,7 @@
-
+
diff --git a/com.microsoft.java.debug.core/pom.xml b/com.microsoft.java.debug.core/pom.xml
index d63b93c01..8bfdb7292 100644
--- a/com.microsoft.java.debug.core/pom.xml
+++ b/com.microsoft.java.debug.core/pom.xml
@@ -42,7 +42,7 @@
org.apache.commons
commons-lang3
- 3.6
+ 3.18.0
com.google.code.gson
diff --git a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java
index 82859b268..d8316c2e3 100644
--- a/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java
+++ b/com.microsoft.java.debug.core/src/main/java/com/microsoft/java/debug/core/Breakpoint.java
@@ -42,24 +42,28 @@ public class Breakpoint implements IBreakpoint {
private String condition = null;
private String logMessage = null;
private HashMap