From 895bae33c72989bb36df0e38e1f78e6852604e81 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 25 Jun 2026 09:27:11 +0800 Subject: [PATCH 1/5] Support VSIX downloads from Actions runs Resolve workflow_dispatch VSIX inputs from GitHub Actions run URLs or redhat-developer/vscode-java run IDs, then select the runner-specific VSIX from the run artifact. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2e-autotest.yml | 94 +++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e-autotest.yml b/.github/workflows/e2e-autotest.yml index db4d2998..83900ad2 100644 --- a/.github/workflows/e2e-autotest.yml +++ b/.github/workflows/e2e-autotest.yml @@ -15,7 +15,7 @@ on: default: "" type: string vsix_urls: - description: "VSIX URLs or GitHub release tag URLs, comma-separated (e.g. https://github.com/redhat-developer/vscode-java/releases/tag/v1.54.0,https://host/vscode-java-debug-0.58.0.vsix). Release tag URLs auto-resolve to the platform-specific VSIX for the runner OS." + description: "VSIX URLs, GitHub release tag URLs, GitHub Actions run URLs, or redhat-developer/vscode-java run IDs, comma-separated (e.g. https://github.com/redhat-developer/vscode-java/releases/tag/v1.54.0,https://github.com/redhat-developer/vscode-java/actions/runs/28102068371,https://host/vscode-java-debug-0.58.0.vsix). Release/run inputs auto-resolve to the platform-specific VSIX for the runner OS." required: false default: "" type: string @@ -27,6 +27,7 @@ on: permissions: contents: read + actions: read jobs: # ── Job 1a: Build vscode-java-pack VSIX from the PR branch ─────── @@ -169,6 +170,9 @@ jobs: - name: Download VSIX files if: ${{ github.event_name == 'workflow_dispatch' && inputs.vsix_urls != '' }} shell: pwsh + env: + GITHUB_TOKEN: ${{ github.token }} + VSCODE_JAVA_ARTIFACT_TOKEN: ${{ secrets.VSCODE_JAVA_ARTIFACT_TOKEN }} run: | New-Item -ItemType Directory -Path vsix -Force | Out-Null $urls = "${{ inputs.vsix_urls }}" -split "," | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" } @@ -181,13 +185,95 @@ jobs: $platformId = "$platform-$arch" Write-Host "Runner platform: $platformId (${{ runner.os }}/${{ runner.arch }})" + $githubHeaders = @{ + Accept = "application/vnd.github+json" + "X-GitHub-Api-Version" = "2022-11-28" + "User-Agent" = "vscode-java-pack-autotest" + } + $artifactToken = if ($env:VSCODE_JAVA_ARTIFACT_TOKEN) { $env:VSCODE_JAVA_ARTIFACT_TOKEN } else { $env:GITHUB_TOKEN } + $githubArtifactHeaders = $githubHeaders.Clone() + if ($artifactToken) { + $githubArtifactHeaders.Authorization = "Bearer $artifactToken" + } + $githubArtifactListHeaders = if ($env:VSCODE_JAVA_ARTIFACT_TOKEN) { $githubArtifactHeaders } else { $githubHeaders } + + function Select-VsixForPlatform { + param( + [Parameter(Mandatory = $true)] + [System.IO.FileInfo[]] $VsixFiles, + [Parameter(Mandatory = $true)] + [string] $PlatformId + ) + + $platformVsix = $VsixFiles | Where-Object { $_.Name -like "*-$PlatformId-*" } | Sort-Object Name | Select-Object -First 1 + if ($platformVsix) { + Write-Host " Found platform-specific VSIX: $($platformVsix.Name)" + return $platformVsix + } + + $universalVsix = $VsixFiles | Where-Object { $_.Name -notmatch '-(darwin|linux|win32)-' } | Sort-Object Name | Select-Object -First 1 + if ($universalVsix) { + Write-Host " No platform-specific VSIX found, using universal: $($universalVsix.Name)" + return $universalVsix + } + + throw "No matching VSIX found for platform $PlatformId. Available VSIX files: $($VsixFiles.Name -join ', ')" + } + + function Download-GitHubActionsRunVsix { + param( + [Parameter(Mandatory = $true)] + [string] $Owner, + [Parameter(Mandatory = $true)] + [string] $Repo, + [Parameter(Mandatory = $true)] + [string] $RunId + ) + + Write-Host "Resolving GitHub Actions run: $Owner/$Repo#$RunId for platform $platformId" + $artifactsUrl = "https://api.github.com/repos/$Owner/$Repo/actions/runs/$RunId/artifacts" + $artifacts = @((Invoke-RestMethod -Uri $artifactsUrl -Headers $githubArtifactListHeaders -UseBasicParsing).artifacts | Where-Object { -not $_.expired }) + if (-not $artifacts) { + throw "No non-expired artifacts found for GitHub Actions run $Owner/$Repo#$RunId" + } + + $artifact = $artifacts | Where-Object { $_.name -eq "vscode-java" } | Select-Object -First 1 + if (-not $artifact -and $artifacts.Count -eq 1) { + $artifact = $artifacts | Select-Object -First 1 + } + if (-not $artifact) { + throw "No vscode-java artifact found for GitHub Actions run $Owner/$Repo#$RunId. Available artifacts: $($artifacts.name -join ', ')" + } + + $safeArtifactName = $artifact.name -replace '[^\w.-]', '_' + $downloadDir = Join-Path "downloaded-artifacts" "$Owner-$Repo-$RunId-$safeArtifactName" + $zipPath = "$downloadDir.zip" + New-Item -ItemType Directory -Path $downloadDir -Force | Out-Null + + Write-Host " Downloading artifact: $($artifact.name)" + try { + Invoke-WebRequest -Uri $artifact.archive_download_url -OutFile $zipPath -Headers $githubArtifactHeaders -UseBasicParsing + } catch { + throw "Failed to download artifact $($artifact.name) from $Owner/$Repo#$RunId. Cross-repo artifact downloads may require a VSCODE_JAVA_ARTIFACT_TOKEN secret with actions:read access to the source repository. $($_.Exception.Message)" + } + Expand-Archive -LiteralPath $zipPath -DestinationPath $downloadDir -Force + + $vsixFiles = @(Get-ChildItem $downloadDir -Recurse -Filter "*.vsix") + if ($vsixFiles.Count -eq 0) { + throw "Artifact $($artifact.name) from $Owner/$Repo#$RunId does not contain VSIX files" + } + + $selectedVsix = Select-VsixForPlatform -VsixFiles $vsixFiles -PlatformId $platformId + Copy-Item -LiteralPath $selectedVsix.FullName -Destination (Join-Path "vsix" $selectedVsix.Name) -Force + } + $resolvedUrls = @() foreach ($url in $urls) { if ($url -match '^https://github\.com/([^/]+)/([^/]+)/releases/tag/(.+)$') { $owner = $Matches[1]; $repo = $Matches[2]; $tag = $Matches[3] Write-Host "Resolving GitHub release: $owner/$repo@$tag for platform $platformId" $apiUrl = "https://api.github.com/repos/$owner/$repo/releases/tags/$tag" - $release = Invoke-RestMethod -Uri $apiUrl -Headers @{ Accept = "application/vnd.github.v3+json" } -UseBasicParsing + $release = Invoke-RestMethod -Uri $apiUrl -Headers $githubHeaders -UseBasicParsing $platformAsset = $release.assets | Where-Object { $_.name -like "*-$platformId-*" -and $_.name -like "*.vsix" } | Select-Object -First 1 if ($platformAsset) { Write-Host " Found platform-specific VSIX: $($platformAsset.name)" @@ -201,6 +287,10 @@ jobs: Write-Host "::warning::No matching VSIX found in release $owner/$repo@$tag for platform $platformId" } } + } elseif ($url -match '^https://github\.com/([^/]+)/([^/]+)/actions/runs/(\d+)') { + Download-GitHubActionsRunVsix -Owner $Matches[1] -Repo $Matches[2] -RunId $Matches[3] + } elseif ($url -match '^\d+$') { + Download-GitHubActionsRunVsix -Owner "redhat-developer" -Repo "vscode-java" -RunId $url } else { $resolvedUrls += $url } From 87a011f5d1cc51a9ef842a878adae5018e535ff0 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 25 Jun 2026 09:31:27 +0800 Subject: [PATCH 2/5] Authenticate Actions artifact lookup Use the available token when listing workflow run artifacts so manual autotest runs avoid anonymous GitHub API rate limits. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2e-autotest.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/e2e-autotest.yml b/.github/workflows/e2e-autotest.yml index 83900ad2..0605666b 100644 --- a/.github/workflows/e2e-autotest.yml +++ b/.github/workflows/e2e-autotest.yml @@ -195,7 +195,6 @@ jobs: if ($artifactToken) { $githubArtifactHeaders.Authorization = "Bearer $artifactToken" } - $githubArtifactListHeaders = if ($env:VSCODE_JAVA_ARTIFACT_TOKEN) { $githubArtifactHeaders } else { $githubHeaders } function Select-VsixForPlatform { param( @@ -232,7 +231,7 @@ jobs: Write-Host "Resolving GitHub Actions run: $Owner/$Repo#$RunId for platform $platformId" $artifactsUrl = "https://api.github.com/repos/$Owner/$Repo/actions/runs/$RunId/artifacts" - $artifacts = @((Invoke-RestMethod -Uri $artifactsUrl -Headers $githubArtifactListHeaders -UseBasicParsing).artifacts | Where-Object { -not $_.expired }) + $artifacts = @((Invoke-RestMethod -Uri $artifactsUrl -Headers $githubArtifactHeaders -UseBasicParsing).artifacts | Where-Object { -not $_.expired }) if (-not $artifacts) { throw "No non-expired artifacts found for GitHub Actions run $Owner/$Repo#$RunId" } From 429c3ca93441454557c883ad2331c4dd1a205ea7 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 25 Jun 2026 09:38:21 +0800 Subject: [PATCH 3/5] Install branch pack before VSIX overrides Build the vscode-java-pack VSIX for manual autotest runs, download it into the VSIX set, and sort VSIX installation so the pack is installed before supplied overrides such as vscode-java Actions run artifacts. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2e-autotest.yml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/e2e-autotest.yml b/.github/workflows/e2e-autotest.yml index 0605666b..56785509 100644 --- a/.github/workflows/e2e-autotest.yml +++ b/.github/workflows/e2e-autotest.yml @@ -30,9 +30,9 @@ permissions: actions: read jobs: - # ── Job 1a: Build vscode-java-pack VSIX from the PR branch ─────── + # ── Job 1a: Build vscode-java-pack VSIX from the PR/manual branch ─────── build-pack: - if: ${{ github.event_name == 'pull_request' }} + if: ${{ github.event_name != 'schedule' }} runs-on: ubuntu-latest steps: - name: Checkout @@ -50,13 +50,13 @@ jobs: - name: Build extension run: npm run build - - name: Package PR VSIX + - name: Package branch VSIX run: npx @vscode/vsce@latest package -o vscode-java-pack-pr.vsix - - name: Upload PR VSIX + - name: Upload branch VSIX uses: actions/upload-artifact@v4 with: - name: pr-vsix + name: pack-vsix path: vscode-java-pack-pr.vsix retention-days: 1 @@ -87,8 +87,8 @@ jobs: # ── Job 2: Run each test plan in parallel ─────────────── e2e-test: needs: [discover, build-pack] - # build-pack is skipped on schedule/workflow_dispatch — only require it on PRs - if: ${{ always() && needs.discover.result == 'success' && (github.event_name != 'pull_request' || needs.build-pack.result == 'success') }} + # build-pack is skipped on schedule; PR/manual runs install this branch's pack VSIX first. + if: ${{ always() && needs.discover.result == 'success' && (github.event_name == 'schedule' || needs.build-pack.result == 'success') }} runs-on: ${{ matrix.os }} timeout-minutes: 30 strategy: @@ -160,11 +160,11 @@ jobs: # Give Xvfb a moment to start before the autotest CLI launches VS Code. sleep 2 - - name: Download PR VSIX (vscode-java-pack from branch) - if: ${{ github.event_name == 'pull_request' }} + - name: Download vscode-java-pack VSIX (from branch) + if: ${{ github.event_name != 'schedule' }} uses: actions/download-artifact@v4 with: - name: pr-vsix + name: pack-vsix path: vsix - name: Download VSIX files @@ -312,11 +312,14 @@ jobs: run: | $autotestArgs = @("run", "test-plans/${{ matrix.plan }}.yaml") if (Test-Path vsix) { - $vsixFiles = (Get-ChildItem vsix -Filter "*.vsix" | ForEach-Object { $_.FullName }) -join "," + $vsixFiles = (Get-ChildItem vsix -Filter "*.vsix" | + Sort-Object @{ Expression = { if ($_.Name -like "vscode-java-pack*") { 0 } else { 1 } } }, Name | + ForEach-Object { $_.FullName }) -join "," if ($vsixFiles) { $autotestArgs += @("--vsix", $vsixFiles) } } - # PRs test the branch-built VSIX against stable marketplace deps. + # PR/manual runs test the branch-built pack VSIX first, then any + # supplied VSIX overrides such as a vscode-java Actions run artifact. # LLM verification activates automatically when AZURE_OPENAI_* secrets # are available (e.g. internal PRs); fork PRs without secret access # simply skip the LLM step (LLMClient.isConfigured() returns false). From 9f0b42c0970457f88020de1be29917a0bc1f7df2 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 25 Jun 2026 09:48:32 +0800 Subject: [PATCH 4/5] Run VSIX overrides through extension pack For manual autotest runs with supplied VSIX inputs, patch each test plan to use vscode-java-pack as the primary extension so vscode-java is installed through the pack before the supplied vscode-java VSIX override is applied. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2e-autotest.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/e2e-autotest.yml b/.github/workflows/e2e-autotest.yml index 56785509..ccb20914 100644 --- a/.github/workflows/e2e-autotest.yml +++ b/.github/workflows/e2e-autotest.yml @@ -303,6 +303,17 @@ jobs: Write-Host "Downloaded VSIX files:" Get-ChildItem vsix -Filter "*.vsix" | ForEach-Object { Write-Host " $($_.Name) ($([math]::Round($_.Length/1MB, 1)) MB)" } + - name: Use vscode-java-pack as primary extension for VSIX override runs + if: ${{ github.event_name == 'workflow_dispatch' && inputs.vsix_urls != '' }} + shell: pwsh + run: | + $planFile = "test-plans/${{ matrix.plan }}.yaml" + $content = Get-Content $planFile -Raw + $content = $content -replace '(?m)^(\s*)extension:\s*"?redhat\.java"?\s*$', '$1extension: "vscjava.vscode-java-pack"' + $content = $content -replace '(?m)^(\s*)extensions:\s*\r?\n\1\s*-\s*"vscjava\.vscode-java-pack"\s*\r?\n', '' + Set-Content $planFile $content + Write-Host "Patched $planFile to install vscode-java through vscode-java-pack before applying VSIX overrides." + - name: Run ${{ matrix.plan }} shell: pwsh env: From 35e6a88a75281420632d705bde74177918d63253 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 25 Jun 2026 10:05:58 +0800 Subject: [PATCH 5/5] Stabilize basic editing rename scenario Target the class declaration before invoking renameSymbol and skip screenshot-only LLM verification for the Save All step where diagnostics are the deterministic assertion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test-plans/java-basic-editing.yaml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test-plans/java-basic-editing.yaml b/test-plans/java-basic-editing.yaml index c1f8377a..ffb42f3c 100644 --- a/test-plans/java-basic-editing.yaml +++ b/test-plans/java-basic-editing.yaml @@ -99,6 +99,9 @@ steps: verifyProblems: errors: 0 timeout: 60 + # The deterministic diagnostics assertion is the ground truth here; the + # tab dirty indicator is not reliable enough for screenshot-only LLM checks. + skipLlmVerify: true # ══════════════════════════════════════════════════════════ # Steps 6-8: Completion, Organize Imports, Rename @@ -155,9 +158,16 @@ steps: verify: "Foo.java is open in editor" timeout: 10 - # Place cursor on "Foo" — use Find to locate the text, then close Find (cursor stays on it) - - id: "find-foo-class" - action: "findText Foo" + # Place the cursor inside the class declaration's "Foo". Searching just + # "Foo" can hit the Javadoc text first, where Java rename is unsupported. + - id: "find-foo-class-declaration" + action: "findText public class Foo" + + - id: "collapse-selection-to-declaration-end" + action: "pressKey ArrowRight" + + - id: "move-cursor-into-class-name" + action: "pressKey ArrowLeft" - id: "rename-foo-to-foonew" action: "renameSymbol FooNew"