From faf9ac4ca0a1501aa96e25e583a86b64aeec9193 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 28 May 2026 10:42:03 +0800 Subject: [PATCH 1/6] =?UTF-8?q?test:=20phase=20A=20coverage=20=E2=80=94=20?= =?UTF-8?q?newJavaRecord,=20clean.workspace,=20project.update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds three more vscode-java-dependency commands to the E2E plans, each exercised through its documented user-visible UI surface: * java-dep-new-types.yaml - Adds a 7th cycle for newJavaRecord between Annotation and Abstract Class. The Record option is filtered out for projects below Java 16 (see JavaType.getDisplayNames in src/explorerCommands/new.ts); the fixture pom.xml is Java 17 so the option renders. Plan goes from 64 → 75 steps. * java-dep-build-lifecycle.yaml - Adds Test 6: java.project.update via the Maven submenu on the project context menu (the command's only UI mount — no palette, no toolbar). Uses the new 'contextMenuSubmenu' autotest action that hovers a submenu trigger then clicks a leaf inside the nested menu. - Adds Test 7: java.project.clean.workspace via the view-title overflow menu. The command may or may not raise a confirmation dialog depending on JDT.LS state; we use the tolerant tryClickDialogButton variant so the step passes either way (cancelling the dialog if shown, avoiding the destructive VS Code reload). Plan goes from 18 → 26 steps. Requires @vscjava/vscode-autotest >= 0.7.11 (adds contextMenuSubmenu). Locally verified: java-dep-new-types.yaml 75/75 passing java-dep-build-lifecycle.yaml 26/26 passing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/e2e-plans/java-dep-build-lifecycle.yaml | 54 ++++++++++++- test/e2e-plans/java-dep-new-types.yaml | 80 +++++++++++++++----- 2 files changed, 111 insertions(+), 23 deletions(-) diff --git a/test/e2e-plans/java-dep-build-lifecycle.yaml b/test/e2e-plans/java-dep-build-lifecycle.yaml index ab650c0a..b0f6df66 100644 --- a/test/e2e-plans/java-dep-build-lifecycle.yaml +++ b/test/e2e-plans/java-dep-build-lifecycle.yaml @@ -12,10 +12,8 @@ # - java.project.build.project (Build Project — project context menu) # - java.project.rebuild (Rebuild Project — project context menu) # - java.project.reloadProjectFromActiveFile (Reload Project — pom.xml editor title) -# -# Note: java.project.clean.workspace is intentionally omitted from this plan -# because the JDT.LS clean command triggers a VS Code window reload, which -# tears down the autotest browser session. +# - java.project.update (Reload Project — Maven submenu on project context menu) +# - java.project.clean.workspace (Clean Workspace — view-title overflow; dialog cancelled to avoid VS Code reload) # # Verification strategy # ───────────────────── @@ -165,3 +163,51 @@ steps: - id: "wait-reload-project" action: "waitForLanguageServer" timeout: 180 + + # ── Test 6: Reload Project (Maven submenu on project context menu) ── + # `java.project.update` lives in the `javaProject.maven` submenu under the + # project context menu's `9_configuration@10` group. Real users right-click + # the Maven project node → hover the "Maven" submenu → click "Reload + # Project". This is the only UI surface for this command (no command + # palette entry, no toolbar button). + - id: "close-pom-editors" + action: "run command View: Close All Editors" + + - id: "focus-java-projects-reload" + action: "executeVSCodeCommand javaProjectExplorer.focus" + waitBefore: 1 + + - id: "click-project-update" + action: "click my-app tree item" + waitBefore: 1 + + - id: "context-update-maven" + action: 'contextMenuSubmenu my-app Maven "Reload Project"' + + - id: "wait-update-project" + action: "waitForLanguageServer" + timeout: 180 + + # ── Test 7: Clean Workspace (overflow menu, dialog cancelled if shown) ── + # `java.project.clean.workspace` is contributed to the Java Projects view + # title-bar `overflow_20@10` group. When clicked it forwards to JDT.LS's + # `java.clean.workspace`. Depending on the redhat.java / JDT.LS version + # this may or may not raise a modal warning dialog ("…delete workspace + # cache and restart?") before doing the work. We use a *tolerant* dialog + # cancel (`tryClickDialogButton`) so the step passes whether or not the + # dialog appears — when it does appear we cancel to avoid the destructive + # VS Code reload; when it does not we proceed straight to the LS settle + # check. The primary coverage signal is the overflow-menu mount + click, + # which `trigger-clean-workspace` already exercises with a deterministic + # `clickViewTitleAction`. + - id: "trigger-clean-workspace" + action: 'clickViewTitleAction "Java Projects" "Clean Workspace"' + + - id: "cancel-clean-dialog" + action: "tryClickDialogButton Cancel" + # No `verify:` — tolerant action: clicks Cancel if dialog appears, else + # silently no-ops. `trigger-clean-workspace` is the deterministic signal. + + - id: "wait-clean-settle" + action: "waitForLanguageServer" + timeout: 60 diff --git a/test/e2e-plans/java-dep-new-types.yaml b/test/e2e-plans/java-dep-new-types.yaml index 1477737c..4e717895 100644 --- a/test/e2e-plans/java-dep-new-types.yaml +++ b/test/e2e-plans/java-dep-new-types.yaml @@ -7,6 +7,7 @@ # Commands exercised (each invoked through the New... quick-pick on a node): # - java.view.package.newJavaInterface (Interface) # - java.view.package.newJavaEnum (Enum) +# - java.view.package.newJavaRecord (Record — requires Java 16+) # - java.view.package.newJavaAnnotation (Annotation) # - java.view.package.newJavaAbstractClass (Abstract Class) # - java.view.package.newFile ("File" option) @@ -31,7 +32,7 @@ name: "Java Dependency — New File Types" description: | Tests all the "New ..." quick-pick options in the Java Projects view that are not already covered by java-dep-file-operations.yaml: - Interface / Enum / Annotation / Abstract Class / File / Folder. + Interface / Enum / Record / Annotation / Abstract Class / File / Folder. setup: extension: "redhat.java" @@ -190,7 +191,9 @@ steps: action: "executeVSCodeCommand javaProjectExplorer.focus" waitBefore: 1 - # ── Test 4: New Abstract Class ── + # ── Test 4: New Record (Java 16+; fixture pom uses Java 17) ── + # The Record option is only shown when the project source level is >= 16, + # see JavaType.getDisplayNames(..., includeRecord) in src/explorerCommands/new.ts. - id: "click-project-4" action: "click my-app tree item" waitBefore: 1 @@ -198,19 +201,19 @@ steps: - id: "trigger-new-4" action: "clickTreeItemAction my-app New..." - - id: "select-abstract-class" - action: "select Abstract Class option" + - id: "select-record" + action: "select Record option" - id: "select-source-folder-4" action: "select src/main/java option" - - id: "enter-abstract-name" - action: "fillQuickInput MyAbstract" + - id: "enter-record-name" + action: "fillQuickInput MyRecord" - - id: "verify-abstract-tab" + - id: "verify-record-tab" action: "wait 2 seconds" verifyEditorTab: - title: "MyAbstract.java" + title: "MyRecord.java" timeout: 20 - id: "save-4" @@ -229,9 +232,7 @@ steps: action: "executeVSCodeCommand javaProjectExplorer.focus" waitBefore: 1 - # ── Test 5: New File (plain non-Java file via "File" option) ── - # The "File" entry routes to `java.view.package.newFile` and writes the - # file under the project root (the node we triggered from). + # ── Test 5: New Abstract Class ── - id: "click-project-5" action: "click my-app tree item" waitBefore: 1 @@ -239,6 +240,47 @@ steps: - id: "trigger-new-5" action: "clickTreeItemAction my-app New..." + - id: "select-abstract-class" + action: "select Abstract Class option" + + - id: "select-source-folder-5" + action: "select src/main/java option" + + - id: "enter-abstract-name" + action: "fillQuickInput MyAbstract" + + - id: "verify-abstract-tab" + action: "wait 2 seconds" + verifyEditorTab: + title: "MyAbstract.java" + timeout: 20 + + - id: "save-5" + action: "executeVSCodeCommand workbench.action.files.saveAll" + + - id: "close-editors-5" + action: "run command View: Close All Editors" + + - id: "collapse-tree-5" + action: 'clickViewTitleAction "Java Projects" "Collapse All"' + + - id: "collapse-workspace-root-6" + action: "collapseWorkspaceRoot" + + - id: "focus-java-projects-6" + action: "executeVSCodeCommand javaProjectExplorer.focus" + waitBefore: 1 + + # ── Test 6: New File (plain non-Java file via "File" option) ── + # The "File" entry routes to `java.view.package.newFile` and writes the + # file under the project root (the node we triggered from). + - id: "click-project-6" + action: "click my-app tree item" + waitBefore: 1 + + - id: "trigger-new-6" + action: "clickTreeItemAction my-app New..." + - id: "select-file" action: "select File option" @@ -251,30 +293,30 @@ steps: title: "notes.txt" timeout: 20 - - id: "save-5" + - id: "save-6" action: "executeVSCodeCommand workbench.action.files.saveAll" - - id: "close-editors-5" + - id: "close-editors-6" action: "run command View: Close All Editors" - - id: "collapse-tree-5" + - id: "collapse-tree-6" action: 'clickViewTitleAction "Java Projects" "Collapse All"' - - id: "collapse-workspace-root-6" + - id: "collapse-workspace-root-7" action: "collapseWorkspaceRoot" - - id: "focus-java-projects-6" + - id: "focus-java-projects-7" action: "executeVSCodeCommand javaProjectExplorer.focus" waitBefore: 1 - # ── Test 6: New Folder ── + # ── Test 7: New Folder ── # Folder creation has no editor side-effect — verify by checking the new # folder exists on disk under the workspace root. - - id: "click-project-6" + - id: "click-project-7" action: "click my-app tree item" waitBefore: 1 - - id: "trigger-new-6" + - id: "trigger-new-7" action: "clickTreeItemAction my-app New..." - id: "select-folder" From 214a5672afffb68ba2fd57b270b61d22f3d15c95 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Thu, 4 Jun 2026 15:09:05 +0800 Subject: [PATCH 2/6] ci(e2e): parallelize UI tests across plans with matrix strategy Refactor linuxUI.yml and windowsUI.yml from a single sequential job running autotest run-all into a 5-job parallel pipeline modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml: 1. build-: produce VSIX once, upload as artifact 2. discover-plans: scan test/e2e-plans/*.yaml -> matrix output 3. e2e- (matrix per plan): download VSIX, run a single plan 4. analyze-: aggregate results.json across plans into summary.md 5. linux-ui / windows-ui: gate job preserving the original required status-check name so existing branch protection keeps working Per-job timeout drops to 25 min and individual plan failures surface independently. Sub-screenshots from each plan are preserved per-plan in their own artifact for easier triage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/linuxUI.yml | 272 ++++++++++++++++++++++++-------- .github/workflows/windowsUI.yml | 265 ++++++++++++++++++++++++------- 2 files changed, 412 insertions(+), 125 deletions(-) diff --git a/.github/workflows/linuxUI.yml b/.github/workflows/linuxUI.yml index 1ee20df0..7ef44c00 100644 --- a/.github/workflows/linuxUI.yml +++ b/.github/workflows/linuxUI.yml @@ -6,71 +6,215 @@ on: pull_request: branches: [ main ] +# Parallelized E2E pipeline (Linux): +# build-linux → packages VSIX once and uploads as artifact +# discover-plans → emits a matrix of test-plan basenames +# e2e-linux (matrix) → one job per plan, all running in parallel +# analyze-linux → aggregates results.json from every plan +# +# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml. +# Splitting plans across jobs keeps each job well under the per-job +# 30-minute timeout and surfaces individual plan failures independently. + jobs: - linuxUI: + # ── Job 1: Build the VSIX once ────────────────────────── + build-linux: + name: Build VSIX (Linux) + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Node.js modules + run: npm install + + - name: Install VSCE + run: npm install -g @vscode/vsce + + - name: Build OSGi bundle + run: npm run build-server + + - name: Build VSIX file + run: vsce package -o vscode-java-dependency.vsix + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: vsix-linux + path: vscode-java-dependency.vsix + retention-days: 1 + + # ── Job 2: Discover test plans ────────────────────────── + discover-plans: + name: Discover E2E Plans + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.scan.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + + - name: Scan test plans + id: scan + shell: bash + run: | + plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) + echo "matrix=$plans" >> "$GITHUB_OUTPUT" + echo "Found plans: $plans" + + # ── Job 3: Run each plan in parallel ──────────────────── + e2e-linux: + name: Linux-UI (${{ matrix.plan }}) + needs: [ build-linux, discover-plans ] + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Build Environment + run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 + # Use 1920x1080 so the Java Projects view (rendered inside the Explorer + # sidebar) gets enough vertical space. With 1024x768 the sticky + # pane-header overlapped tree rows and intercepted click events. + sudo /usr/bin/Xvfb :99 -screen 0 1920x1080x24 > /dev/null 2>&1 & + sleep 3 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: vsix-linux + path: . + + - name: E2E Test — ${{ matrix.plan }} + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: | + DISPLAY=:99 autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" \ + --vsix "$(pwd)/vscode-java-dependency.vsix" \ + --output "test-results/${{ matrix.plan }}" + + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: e2e-results-linux-${{ matrix.plan }} + path: test-results/ + retention-days: 7 + + # ── Job 4: Aggregate analysis ─────────────────────────── + analyze-linux: + name: Linux-UI Summary + needs: e2e-linux + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download all plan results + uses: actions/download-artifact@v4 + with: + pattern: e2e-results-linux-* + path: all-results + merge-multiple: false + + - name: Organize results + shell: bash + run: | + mkdir -p test-results + for dir in all-results/e2e-results-linux-*/; do + find "$dir" -name "results.json" -exec dirname {} \; | while read d; do + name=$(basename "$d") + mkdir -p "test-results/$name" + cp -r "$d"/. "test-results/$name"/ + done + done + echo "Organized plan result directories:" + ls test-results/ || true + + - name: Analyze results + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: autotest analyze test-results --output test-results + + - name: Write Job Summary + if: always() + shell: bash + run: | + if [ -f test-results/summary.md ]; then + cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" + fi + + - name: Upload aggregate summary + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-aggregate-summary-linux + path: test-results/summary.md + retention-days: 30 + + # ── Job 5: Branch-protection compatibility gate ───────── + # Preserves the original required-status-check name `Linux-UI` + # so existing branch-protection rules keep working without edits. + # Fails if any upstream job did not succeed. + linux-ui: name: Linux-UI + needs: [ build-linux, discover-plans, e2e-linux, analyze-linux ] + if: ${{ always() }} runs-on: ubuntu-latest - timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - - name: Setup Build Environment - run: | - sudo apt-get update - sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 - # Use 1920x1080 so the Java Projects view (rendered inside the Explorer - # sidebar) gets enough vertical space. With 1024x768 the sticky - # pane-header overlapped tree rows and intercepted click events. - sudo /usr/bin/Xvfb :99 -screen 0 1920x1080x24 > /dev/null 2>&1 & - sleep 3 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install Node.js modules - run: npm install - - - name: Install VSCE - run: npm install -g @vscode/vsce - - - name: Build OSGi bundle - run: npm run build-server - - - name: Build VSIX file - run: vsce package -o vscode-java-dependency.vsix - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: E2E Test (autotest) - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: | - DISPLAY=:99 autotest run-all test/e2e-plans \ - --vsix $(pwd)/vscode-java-dependency.vsix \ - --output test-results - - - name: Upload test results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: e2e-results-linux - path: test-results/ - retention-days: 7 - - - name: Write Job Summary - if: always() - run: | - if [ -f test-results/summary.md ]; then - cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" - fi + - name: Verify required jobs + shell: bash + run: | + echo "build-linux: ${{ needs.build-linux.result }}" + echo "discover-plans: ${{ needs.discover-plans.result }}" + echo "e2e-linux: ${{ needs.e2e-linux.result }}" + echo "analyze-linux: ${{ needs.analyze-linux.result }}" + if [ "${{ needs.build-linux.result }}" != "success" ] || \ + [ "${{ needs.discover-plans.result }}" != "success" ] || \ + [ "${{ needs.e2e-linux.result }}" != "success" ] || \ + [ "${{ needs.analyze-linux.result }}" != "success" ]; then + echo "::error::One or more required Linux-UI jobs failed" + exit 1 + fi + diff --git a/.github/workflows/windowsUI.yml b/.github/workflows/windowsUI.yml index c92c6640..4ea9d7b5 100644 --- a/.github/workflows/windowsUI.yml +++ b/.github/workflows/windowsUI.yml @@ -6,67 +6,210 @@ on: pull_request: branches: [ main ] +# Parallelized E2E pipeline (Windows): +# build-windows → lint + checkstyle + packages VSIX once and uploads +# discover-plans → emits a matrix of test-plan basenames +# e2e-windows (matrix) → one job per plan, all running in parallel +# analyze-windows → aggregates results.json from every plan +# +# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml. +# Splitting plans across jobs keeps each job well under the per-job +# 30-minute timeout and surfaces individual plan failures independently. + jobs: - windowsUI: - name: Windows-UI + # ── Job 1: Lint + Checkstyle + Build the VSIX once ────── + build-windows: + name: Build VSIX (Windows) + runs-on: windows-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Node.js modules + run: npm install + + - name: Install VSCE + run: npm install -g @vscode/vsce + + - name: Lint + run: npm run tslint + + - name: Checkstyle + working-directory: .\jdtls.ext + run: .\mvnw.cmd checkstyle:check + + - name: Build OSGi bundle + run: npm run build-server + + - name: Build VSIX file + run: vsce package -o vscode-java-dependency.vsix + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: vsix-windows + path: vscode-java-dependency.vsix + retention-days: 1 + + # ── Job 2: Discover test plans ────────────────────────── + discover-plans: + name: Discover E2E Plans + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.scan.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + + - name: Scan test plans + id: scan + shell: bash + run: | + plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) + echo "matrix=$plans" >> "$GITHUB_OUTPUT" + echo "Found plans: $plans" + + # ── Job 3: Run each plan in parallel ──────────────────── + e2e-windows: + name: Windows-UI (${{ matrix.plan }}) + needs: [ build-windows, discover-plans ] runs-on: windows-latest - timeout-minutes: 30 + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} + steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install Node.js modules - run: npm install - - - name: Install VSCE - run: npm install -g @vscode/vsce - - - name: Lint - run: npm run tslint - - - name: Checkstyle - working-directory: .\jdtls.ext - run: .\mvnw.cmd checkstyle:check - - - name: Build OSGi bundle - run: npm run build-server - - - name: Build VSIX file - run: vsce package -o vscode-java-dependency.vsix - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: E2E Test (autotest) - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: | - autotest run-all test/e2e-plans --vsix "$((Get-Location).Path)\vscode-java-dependency.vsix" --output test-results - - - name: Upload test results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: e2e-results-windows - path: test-results/ - retention-days: 7 - - - name: Write Job Summary - if: always() - shell: bash - run: | - if [ -f test-results/summary.md ]; then - cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" - fi + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: vsix-windows + path: . + + - name: E2E Test — ${{ matrix.plan }} + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: | + autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" --vsix "$((Get-Location).Path)\vscode-java-dependency.vsix" --output "test-results\${{ matrix.plan }}" + + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: e2e-results-windows-${{ matrix.plan }} + path: test-results/ + retention-days: 7 + + # ── Job 4: Aggregate analysis ─────────────────────────── + analyze-windows: + name: Windows-UI Summary + needs: e2e-windows + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download all plan results + uses: actions/download-artifact@v4 + with: + pattern: e2e-results-windows-* + path: all-results + merge-multiple: false + + - name: Organize results + shell: bash + run: | + mkdir -p test-results + for dir in all-results/e2e-results-windows-*/; do + find "$dir" -name "results.json" -exec dirname {} \; | while read d; do + name=$(basename "$d") + mkdir -p "test-results/$name" + cp -r "$d"/. "test-results/$name"/ + done + done + echo "Organized plan result directories:" + ls test-results/ || true + + - name: Analyze results + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: autotest analyze test-results --output test-results + + - name: Write Job Summary + if: always() + shell: bash + run: | + if [ -f test-results/summary.md ]; then + cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" + fi + + - name: Upload aggregate summary + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-aggregate-summary-windows + path: test-results/summary.md + retention-days: 30 + + # ── Job 5: Branch-protection compatibility gate ───────── + # Preserves the original required-status-check name `Windows-UI` + # so existing branch-protection rules keep working without edits. + # Fails if any upstream job did not succeed. + windows-ui: + name: Windows-UI + needs: [ build-windows, discover-plans, e2e-windows, analyze-windows ] + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Verify required jobs + shell: bash + run: | + echo "build-windows: ${{ needs.build-windows.result }}" + echo "discover-plans: ${{ needs.discover-plans.result }}" + echo "e2e-windows: ${{ needs.e2e-windows.result }}" + echo "analyze-windows: ${{ needs.analyze-windows.result }}" + if [ "${{ needs.build-windows.result }}" != "success" ] || \ + [ "${{ needs.discover-plans.result }}" != "success" ] || \ + [ "${{ needs.e2e-windows.result }}" != "success" ] || \ + [ "${{ needs.analyze-windows.result }}" != "success" ]; then + echo "::error::One or more required Windows-UI jobs failed" + exit 1 + fi + From 6c1d2ddb1828672b9f04741b7961486c390c3cef Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Fri, 5 Jun 2026 11:01:56 +0800 Subject: [PATCH 3/6] ci(e2e): consolidate Linux + Windows UI workflows into one e2eUI.yml Merges the per-OS workflows (linuxUI.yml, windowsUI.yml) into a single e2eUI.yml with a unified entry point and a single shared summary. Structure: - discover-plans (matrix output) - build-linux / build-windows (VSIX artifacts) - e2e-linux / e2e-windows (matrix) (one job per (OS, plan)) - analyze (one combined summary across both OSes, plan dirs prefixed by OS for clarity) - Linux-UI / Windows-UI (gate jobs) (preserve required status-check names) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2eUI.yml | 343 ++++++++++++++++++++++++++++++++ .github/workflows/linuxUI.yml | 220 -------------------- .github/workflows/windowsUI.yml | 215 -------------------- 3 files changed, 343 insertions(+), 435 deletions(-) create mode 100644 .github/workflows/e2eUI.yml delete mode 100644 .github/workflows/linuxUI.yml delete mode 100644 .github/workflows/windowsUI.yml diff --git a/.github/workflows/e2eUI.yml b/.github/workflows/e2eUI.yml new file mode 100644 index 00000000..4e524ec0 --- /dev/null +++ b/.github/workflows/e2eUI.yml @@ -0,0 +1,343 @@ +name: E2E UI Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +# Unified parallel E2E UI pipeline for Linux + Windows. +# +# discover-plans → emits a matrix of test-plan basenames +# build-linux / build-windows → produce VSIX once per OS, upload artifact +# e2e-linux / e2e-windows (matrix)→ one job per (OS, plan), running in parallel +# analyze → aggregates results from BOTH OSes into a +# single unified summary in $GITHUB_STEP_SUMMARY +# Linux-UI / Windows-UI (gate) → preserves the original required-status-check +# names so existing branch-protection keeps working +# +# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml, +# but consolidates the two former workflows (linuxUI.yml, windowsUI.yml) +# into one file with one shared summary. + +jobs: + # ── Discover test plans ───────────────────────────────── + discover-plans: + name: Discover E2E Plans + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.scan.outputs.matrix }} + steps: + - uses: actions/checkout@v4 + + - name: Scan test plans + id: scan + shell: bash + run: | + plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) + echo "matrix=$plans" >> "$GITHUB_OUTPUT" + echo "Found plans: $plans" + + # ── Build VSIX (Linux) ────────────────────────────────── + build-linux: + name: Build VSIX (Linux) + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Node.js modules + run: npm install + + - name: Install VSCE + run: npm install -g @vscode/vsce + + - name: Build OSGi bundle + run: npm run build-server + + - name: Build VSIX file + run: vsce package -o vscode-java-dependency.vsix + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: vsix-linux + path: vscode-java-dependency.vsix + retention-days: 1 + + # ── Build VSIX (Windows) — also runs lint + checkstyle ── + build-windows: + name: Build VSIX (Windows) + runs-on: windows-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Node.js modules + run: npm install + + - name: Install VSCE + run: npm install -g @vscode/vsce + + - name: Lint + run: npm run tslint + + - name: Checkstyle + working-directory: .\jdtls.ext + run: .\mvnw.cmd checkstyle:check + + - name: Build OSGi bundle + run: npm run build-server + + - name: Build VSIX file + run: vsce package -o vscode-java-dependency.vsix + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: vsix-windows + path: vscode-java-dependency.vsix + retention-days: 1 + + # ── Run each plan in parallel (Linux) ─────────────────── + e2e-linux: + name: Linux (${{ matrix.plan }}) + needs: [ build-linux, discover-plans ] + runs-on: ubuntu-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + - name: Setup Build Environment + run: | + sudo apt-get update + sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 + # Use 1920x1080 so the Java Projects view (rendered inside the Explorer + # sidebar) gets enough vertical space. With 1024x768 the sticky + # pane-header overlapped tree rows and intercepted click events. + sudo /usr/bin/Xvfb :99 -screen 0 1920x1080x24 > /dev/null 2>&1 & + sleep 3 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: vsix-linux + path: . + + - name: E2E Test — ${{ matrix.plan }} + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: | + DISPLAY=:99 autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" \ + --vsix "$(pwd)/vscode-java-dependency.vsix" \ + --output "test-results/${{ matrix.plan }}" + + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: e2e-results-linux-${{ matrix.plan }} + path: test-results/ + retention-days: 7 + + # ── Run each plan in parallel (Windows) ───────────────── + e2e-windows: + name: Windows (${{ matrix.plan }}) + needs: [ build-windows, discover-plans ] + runs-on: windows-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: vsix-windows + path: . + + - name: E2E Test — ${{ matrix.plan }} + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: | + autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" --vsix "$((Get-Location).Path)\vscode-java-dependency.vsix" --output "test-results\${{ matrix.plan }}" + + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: e2e-results-windows-${{ matrix.plan }} + path: test-results/ + retention-days: 7 + + # ── Unified analysis across both OSes ─────────────────── + analyze: + name: E2E Summary + needs: [ e2e-linux, e2e-windows ] + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download all plan results + uses: actions/download-artifact@v4 + with: + pattern: e2e-results-* + path: all-results + merge-multiple: false + + - name: Organize results (prefix each plan by OS) + shell: bash + run: | + mkdir -p test-results + for dir in all-results/e2e-results-linux-*/; do + find "$dir" -name "results.json" -exec dirname {} \; | while read d; do + name=$(basename "$d") + mkdir -p "test-results/linux-$name" + cp -r "$d"/. "test-results/linux-$name"/ + done + done + for dir in all-results/e2e-results-windows-*/; do + find "$dir" -name "results.json" -exec dirname {} \; | while read d; do + name=$(basename "$d") + mkdir -p "test-results/windows-$name" + cp -r "$d"/. "test-results/windows-$name"/ + done + done + echo "Organized plan result directories:" + ls test-results/ || true + + - name: Analyze results + env: + AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} + AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} + AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} + run: autotest analyze test-results --output test-results + + - name: Write Job Summary + if: always() + shell: bash + run: | + if [ -f test-results/summary.md ]; then + cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" + fi + + - name: Upload aggregate summary + if: always() + uses: actions/upload-artifact@v4 + with: + name: e2e-aggregate-summary + path: test-results/summary.md + retention-days: 30 + + # ── Branch-protection compatibility gates ─────────────── + # Preserve the original required-status-check names so existing + # branch-protection rules keep working without edits. Each gate + # checks only its own OS's pipeline (analyze is shared and excluded + # so a per-OS gate can pass/fail independently). + Linux-UI: + name: Linux-UI + needs: [ build-linux, discover-plans, e2e-linux ] + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Verify Linux jobs + shell: bash + run: | + echo "build-linux: ${{ needs.build-linux.result }}" + echo "discover-plans: ${{ needs.discover-plans.result }}" + echo "e2e-linux: ${{ needs.e2e-linux.result }}" + if [ "${{ needs.build-linux.result }}" != "success" ] || \ + [ "${{ needs.discover-plans.result }}" != "success" ] || \ + [ "${{ needs.e2e-linux.result }}" != "success" ]; then + echo "::error::One or more Linux-UI jobs failed" + exit 1 + fi + + Windows-UI: + name: Windows-UI + needs: [ build-windows, discover-plans, e2e-windows ] + if: ${{ always() }} + runs-on: ubuntu-latest + steps: + - name: Verify Windows jobs + shell: bash + run: | + echo "build-windows: ${{ needs.build-windows.result }}" + echo "discover-plans: ${{ needs.discover-plans.result }}" + echo "e2e-windows: ${{ needs.e2e-windows.result }}" + if [ "${{ needs.build-windows.result }}" != "success" ] || \ + [ "${{ needs.discover-plans.result }}" != "success" ] || \ + [ "${{ needs.e2e-windows.result }}" != "success" ]; then + echo "::error::One or more Windows-UI jobs failed" + exit 1 + fi diff --git a/.github/workflows/linuxUI.yml b/.github/workflows/linuxUI.yml deleted file mode 100644 index 7ef44c00..00000000 --- a/.github/workflows/linuxUI.yml +++ /dev/null @@ -1,220 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -# Parallelized E2E pipeline (Linux): -# build-linux → packages VSIX once and uploads as artifact -# discover-plans → emits a matrix of test-plan basenames -# e2e-linux (matrix) → one job per plan, all running in parallel -# analyze-linux → aggregates results.json from every plan -# -# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml. -# Splitting plans across jobs keeps each job well under the per-job -# 30-minute timeout and surfaces individual plan failures independently. - -jobs: - # ── Job 1: Build the VSIX once ────────────────────────── - build-linux: - name: Build VSIX (Linux) - runs-on: ubuntu-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install Node.js modules - run: npm install - - - name: Install VSCE - run: npm install -g @vscode/vsce - - - name: Build OSGi bundle - run: npm run build-server - - - name: Build VSIX file - run: vsce package -o vscode-java-dependency.vsix - - - name: Upload VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: vsix-linux - path: vscode-java-dependency.vsix - retention-days: 1 - - # ── Job 2: Discover test plans ────────────────────────── - discover-plans: - name: Discover E2E Plans - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.scan.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - - - name: Scan test plans - id: scan - shell: bash - run: | - plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) - echo "matrix=$plans" >> "$GITHUB_OUTPUT" - echo "Found plans: $plans" - - # ── Job 3: Run each plan in parallel ──────────────────── - e2e-linux: - name: Linux-UI (${{ matrix.plan }}) - needs: [ build-linux, discover-plans ] - runs-on: ubuntu-latest - timeout-minutes: 25 - strategy: - fail-fast: false - matrix: - plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} - - steps: - - uses: actions/checkout@v4 - - - name: Setup Build Environment - run: | - sudo apt-get update - sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 - # Use 1920x1080 so the Java Projects view (rendered inside the Explorer - # sidebar) gets enough vertical space. With 1024x768 the sticky - # pane-header overlapped tree rows and intercepted click events. - sudo /usr/bin/Xvfb :99 -screen 0 1920x1080x24 > /dev/null 2>&1 & - sleep 3 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: Download VSIX artifact - uses: actions/download-artifact@v4 - with: - name: vsix-linux - path: . - - - name: E2E Test — ${{ matrix.plan }} - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: | - DISPLAY=:99 autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" \ - --vsix "$(pwd)/vscode-java-dependency.vsix" \ - --output "test-results/${{ matrix.plan }}" - - - name: Upload test results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: e2e-results-linux-${{ matrix.plan }} - path: test-results/ - retention-days: 7 - - # ── Job 4: Aggregate analysis ─────────────────────────── - analyze-linux: - name: Linux-UI Summary - needs: e2e-linux - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: Download all plan results - uses: actions/download-artifact@v4 - with: - pattern: e2e-results-linux-* - path: all-results - merge-multiple: false - - - name: Organize results - shell: bash - run: | - mkdir -p test-results - for dir in all-results/e2e-results-linux-*/; do - find "$dir" -name "results.json" -exec dirname {} \; | while read d; do - name=$(basename "$d") - mkdir -p "test-results/$name" - cp -r "$d"/. "test-results/$name"/ - done - done - echo "Organized plan result directories:" - ls test-results/ || true - - - name: Analyze results - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: autotest analyze test-results --output test-results - - - name: Write Job Summary - if: always() - shell: bash - run: | - if [ -f test-results/summary.md ]; then - cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" - fi - - - name: Upload aggregate summary - if: always() - uses: actions/upload-artifact@v4 - with: - name: e2e-aggregate-summary-linux - path: test-results/summary.md - retention-days: 30 - - # ── Job 5: Branch-protection compatibility gate ───────── - # Preserves the original required-status-check name `Linux-UI` - # so existing branch-protection rules keep working without edits. - # Fails if any upstream job did not succeed. - linux-ui: - name: Linux-UI - needs: [ build-linux, discover-plans, e2e-linux, analyze-linux ] - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Verify required jobs - shell: bash - run: | - echo "build-linux: ${{ needs.build-linux.result }}" - echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e-linux: ${{ needs.e2e-linux.result }}" - echo "analyze-linux: ${{ needs.analyze-linux.result }}" - if [ "${{ needs.build-linux.result }}" != "success" ] || \ - [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e-linux.result }}" != "success" ] || \ - [ "${{ needs.analyze-linux.result }}" != "success" ]; then - echo "::error::One or more required Linux-UI jobs failed" - exit 1 - fi - diff --git a/.github/workflows/windowsUI.yml b/.github/workflows/windowsUI.yml deleted file mode 100644 index 4ea9d7b5..00000000 --- a/.github/workflows/windowsUI.yml +++ /dev/null @@ -1,215 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -# Parallelized E2E pipeline (Windows): -# build-windows → lint + checkstyle + packages VSIX once and uploads -# discover-plans → emits a matrix of test-plan basenames -# e2e-windows (matrix) → one job per plan, all running in parallel -# analyze-windows → aggregates results.json from every plan -# -# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml. -# Splitting plans across jobs keeps each job well under the per-job -# 30-minute timeout and surfaces individual plan failures independently. - -jobs: - # ── Job 1: Lint + Checkstyle + Build the VSIX once ────── - build-windows: - name: Build VSIX (Windows) - runs-on: windows-latest - timeout-minutes: 20 - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Install Node.js modules - run: npm install - - - name: Install VSCE - run: npm install -g @vscode/vsce - - - name: Lint - run: npm run tslint - - - name: Checkstyle - working-directory: .\jdtls.ext - run: .\mvnw.cmd checkstyle:check - - - name: Build OSGi bundle - run: npm run build-server - - - name: Build VSIX file - run: vsce package -o vscode-java-dependency.vsix - - - name: Upload VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: vsix-windows - path: vscode-java-dependency.vsix - retention-days: 1 - - # ── Job 2: Discover test plans ────────────────────────── - discover-plans: - name: Discover E2E Plans - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.scan.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - - - name: Scan test plans - id: scan - shell: bash - run: | - plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) - echo "matrix=$plans" >> "$GITHUB_OUTPUT" - echo "Found plans: $plans" - - # ── Job 3: Run each plan in parallel ──────────────────── - e2e-windows: - name: Windows-UI (${{ matrix.plan }}) - needs: [ build-windows, discover-plans ] - runs-on: windows-latest - timeout-minutes: 25 - strategy: - fail-fast: false - matrix: - plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} - - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: Download VSIX artifact - uses: actions/download-artifact@v4 - with: - name: vsix-windows - path: . - - - name: E2E Test — ${{ matrix.plan }} - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: | - autotest run "test/e2e-plans/${{ matrix.plan }}.yaml" --vsix "$((Get-Location).Path)\vscode-java-dependency.vsix" --output "test-results\${{ matrix.plan }}" - - - name: Upload test results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: e2e-results-windows-${{ matrix.plan }} - path: test-results/ - retention-days: 7 - - # ── Job 4: Aggregate analysis ─────────────────────────── - analyze-windows: - name: Windows-UI Summary - needs: e2e-windows - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: Download all plan results - uses: actions/download-artifact@v4 - with: - pattern: e2e-results-windows-* - path: all-results - merge-multiple: false - - - name: Organize results - shell: bash - run: | - mkdir -p test-results - for dir in all-results/e2e-results-windows-*/; do - find "$dir" -name "results.json" -exec dirname {} \; | while read d; do - name=$(basename "$d") - mkdir -p "test-results/$name" - cp -r "$d"/. "test-results/$name"/ - done - done - echo "Organized plan result directories:" - ls test-results/ || true - - - name: Analyze results - env: - AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} - AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} - AZURE_OPENAI_DEPLOYMENT: ${{ secrets.AZURE_OPENAI_DEPLOYMENT }} - run: autotest analyze test-results --output test-results - - - name: Write Job Summary - if: always() - shell: bash - run: | - if [ -f test-results/summary.md ]; then - cat test-results/summary.md >> "$GITHUB_STEP_SUMMARY" - fi - - - name: Upload aggregate summary - if: always() - uses: actions/upload-artifact@v4 - with: - name: e2e-aggregate-summary-windows - path: test-results/summary.md - retention-days: 30 - - # ── Job 5: Branch-protection compatibility gate ───────── - # Preserves the original required-status-check name `Windows-UI` - # so existing branch-protection rules keep working without edits. - # Fails if any upstream job did not succeed. - windows-ui: - name: Windows-UI - needs: [ build-windows, discover-plans, e2e-windows, analyze-windows ] - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Verify required jobs - shell: bash - run: | - echo "build-windows: ${{ needs.build-windows.result }}" - echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e-windows: ${{ needs.e2e-windows.result }}" - echo "analyze-windows: ${{ needs.analyze-windows.result }}" - if [ "${{ needs.build-windows.result }}" != "success" ] || \ - [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e-windows.result }}" != "success" ] || \ - [ "${{ needs.analyze-windows.result }}" != "success" ]; then - echo "::error::One or more required Windows-UI jobs failed" - exit 1 - fi - From a090c5ed7e659413deccb0cc9ffbbb2e41fcc896 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Fri, 5 Jun 2026 11:08:39 +0800 Subject: [PATCH 4/6] ci(e2e): fold OS into the matrix; extract Lint/Checkstyle to its own job Reworks the e2e workflow so {os, plan} is a single cartesian matrix instead of two parallel jobs (e2e-linux, e2e-windows): - lint tslint + checkstyle (ubuntu, OS-agnostic) - discover-plans - build (matrix on os) - e2e (matrix on {os, plan}) cartesian 2 x N parallel jobs - analyze one combined summary across both OSes - Linux-UI / Windows-UI gates preserve required-check names Inspired by vscode-java-pack/e2e-autotest.yml extended with an OS dimension. OS-specific steps (Xvfb, shell flavor) are guarded by runner.os conditionals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2eUI.yml | 220 +++++++++++++++--------------------- 1 file changed, 91 insertions(+), 129 deletions(-) diff --git a/.github/workflows/e2eUI.yml b/.github/workflows/e2eUI.yml index 4e524ec0..0eb5bb6e 100644 --- a/.github/workflows/e2eUI.yml +++ b/.github/workflows/e2eUI.yml @@ -8,41 +8,24 @@ on: # Unified parallel E2E UI pipeline for Linux + Windows. # -# discover-plans → emits a matrix of test-plan basenames -# build-linux / build-windows → produce VSIX once per OS, upload artifact -# e2e-linux / e2e-windows (matrix)→ one job per (OS, plan), running in parallel -# analyze → aggregates results from BOTH OSes into a -# single unified summary in $GITHUB_STEP_SUMMARY -# Linux-UI / Windows-UI (gate) → preserves the original required-status-check -# names so existing branch-protection keeps working +# lint → tslint + checkstyle (ubuntu, OS-agnostic) +# discover-plans → emits a matrix of test-plan basenames +# build (matrix) → produces one VSIX per OS, uploaded as artifact +# e2e (matrix) → cartesian product of {os × plan}, all running in parallel +# analyze → aggregates results from BOTH OSes into one unified summary +# Linux-UI → branch-protection gate (preserves required-check name) +# Windows-UI → branch-protection gate (preserves required-check name) # -# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml, -# but consolidates the two former workflows (linuxUI.yml, windowsUI.yml) -# into one file with one shared summary. +# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml; matrix +# has been extended with an `os` dimension so a single `e2e` job covers both +# platforms. jobs: - # ── Discover test plans ───────────────────────────────── - discover-plans: - name: Discover E2E Plans - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.scan.outputs.matrix }} - steps: - - uses: actions/checkout@v4 - - - name: Scan test plans - id: scan - shell: bash - run: | - plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) - echo "matrix=$plans" >> "$GITHUB_OUTPUT" - echo "Found plans: $plans" - - # ── Build VSIX (Linux) ────────────────────────────────── - build-linux: - name: Build VSIX (Linux) + # ── Lint + Checkstyle (OS-agnostic) ───────────────────── + lint: + name: Lint & Checkstyle runs-on: ubuntu-latest - timeout-minutes: 20 + timeout-minutes: 10 steps: - uses: actions/checkout@v4 @@ -60,27 +43,39 @@ jobs: - name: Install Node.js modules run: npm install - - name: Install VSCE - run: npm install -g @vscode/vsce + - name: Lint + run: npm run tslint - - name: Build OSGi bundle - run: npm run build-server + - name: Checkstyle + working-directory: ./jdtls.ext + run: ./mvnw checkstyle:check - - name: Build VSIX file - run: vsce package -o vscode-java-dependency.vsix + # ── Discover test plans ───────────────────────────────── + discover-plans: + name: Discover E2E Plans + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.scan.outputs.matrix }} + steps: + - uses: actions/checkout@v4 - - name: Upload VSIX artifact - uses: actions/upload-artifact@v4 - with: - name: vsix-linux - path: vscode-java-dependency.vsix - retention-days: 1 + - name: Scan test plans + id: scan + shell: bash + run: | + plans=$(ls test/e2e-plans/*.yaml | xargs -n1 basename | sed 's/\.yaml$//' | jq -R . | jq -sc .) + echo "matrix=$plans" >> "$GITHUB_OUTPUT" + echo "Found plans: $plans" - # ── Build VSIX (Windows) — also runs lint + checkstyle ── - build-windows: - name: Build VSIX (Windows) - runs-on: windows-latest + # ── Build VSIX (one per OS) ───────────────────────────── + build: + name: Build VSIX (${{ matrix.os }}) + runs-on: ${{ matrix.os }} timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 @@ -101,13 +96,6 @@ jobs: - name: Install VSCE run: npm install -g @vscode/vsce - - name: Lint - run: npm run tslint - - - name: Checkstyle - working-directory: .\jdtls.ext - run: .\mvnw.cmd checkstyle:check - - name: Build OSGi bundle run: npm run build-server @@ -117,25 +105,27 @@ jobs: - name: Upload VSIX artifact uses: actions/upload-artifact@v4 with: - name: vsix-windows + name: vsix-${{ matrix.os }} path: vscode-java-dependency.vsix retention-days: 1 - # ── Run each plan in parallel (Linux) ─────────────────── - e2e-linux: - name: Linux (${{ matrix.plan }}) - needs: [ build-linux, discover-plans ] - runs-on: ubuntu-latest + # ── Run every (OS × plan) combo in parallel ───────────── + e2e: + name: E2E (${{ matrix.os }} / ${{ matrix.plan }}) + needs: [ build, discover-plans ] + runs-on: ${{ matrix.os }} timeout-minutes: 25 strategy: fail-fast: false matrix: + os: [ ubuntu-latest, windows-latest ] plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} steps: - uses: actions/checkout@v4 - - name: Setup Build Environment + - name: Setup Linux Build Environment (Xvfb) + if: runner.os == 'Linux' run: | sudo apt-get update sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 @@ -162,10 +152,12 @@ jobs: - name: Download VSIX artifact uses: actions/download-artifact@v4 with: - name: vsix-linux + name: vsix-${{ matrix.os }} path: . - - name: E2E Test — ${{ matrix.plan }} + - name: E2E Test — ${{ matrix.plan }} (Linux) + if: runner.os == 'Linux' + shell: bash env: AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} @@ -175,49 +167,9 @@ jobs: --vsix "$(pwd)/vscode-java-dependency.vsix" \ --output "test-results/${{ matrix.plan }}" - - name: Upload test results - if: ${{ always() }} - uses: actions/upload-artifact@v4 - with: - name: e2e-results-linux-${{ matrix.plan }} - path: test-results/ - retention-days: 7 - - # ── Run each plan in parallel (Windows) ───────────────── - e2e-windows: - name: Windows (${{ matrix.plan }}) - needs: [ build-windows, discover-plans ] - runs-on: windows-latest - timeout-minutes: 25 - strategy: - fail-fast: false - matrix: - plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} - - steps: - - uses: actions/checkout@v4 - - - name: Set up JDK 21 - uses: actions/setup-java@v4 - with: - java-version: '21' - distribution: 'temurin' - - - name: Setup Node.js environment - uses: actions/setup-node@v4 - with: - node-version: 20 - - - name: Setup autotest - run: npm install -g @vscjava/vscode-autotest - - - name: Download VSIX artifact - uses: actions/download-artifact@v4 - with: - name: vsix-windows - path: . - - - name: E2E Test — ${{ matrix.plan }} + - name: E2E Test — ${{ matrix.plan }} (Windows) + if: runner.os == 'Windows' + shell: pwsh env: AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} AZURE_OPENAI_API_KEY: ${{ secrets.AZURE_OPENAI_API_KEY }} @@ -229,14 +181,14 @@ jobs: if: ${{ always() }} uses: actions/upload-artifact@v4 with: - name: e2e-results-windows-${{ matrix.plan }} + name: e2e-results-${{ matrix.os }}-${{ matrix.plan }} path: test-results/ retention-days: 7 # ── Unified analysis across both OSes ─────────────────── analyze: name: E2E Summary - needs: [ e2e-linux, e2e-windows ] + needs: e2e if: ${{ always() }} runs-on: ubuntu-latest steps: @@ -259,14 +211,18 @@ jobs: shell: bash run: | mkdir -p test-results - for dir in all-results/e2e-results-linux-*/; do + # Artifact dir names look like: e2e-results-ubuntu-latest- + # or e2e-results-windows-latest- + for dir in all-results/e2e-results-ubuntu-latest-*/; do + [ -d "$dir" ] || continue find "$dir" -name "results.json" -exec dirname {} \; | while read d; do name=$(basename "$d") mkdir -p "test-results/linux-$name" cp -r "$d"/. "test-results/linux-$name"/ done done - for dir in all-results/e2e-results-windows-*/; do + for dir in all-results/e2e-results-windows-latest-*/; do + [ -d "$dir" ] || continue find "$dir" -name "results.json" -exec dirname {} \; | while read d; do name=$(basename "$d") mkdir -p "test-results/windows-$name" @@ -300,44 +256,50 @@ jobs: retention-days: 30 # ── Branch-protection compatibility gates ─────────────── - # Preserve the original required-status-check names so existing - # branch-protection rules keep working without edits. Each gate - # checks only its own OS's pipeline (analyze is shared and excluded - # so a per-OS gate can pass/fail independently). + # Preserve the historical required-status-check names so existing + # branch-protection rules keep working without edits. The matrix + # aggregates per-OS results into a single `needs.e2e.result`, so + # both gates reflect the same overall e2e outcome. (If you want + # truly per-OS gates, switch branch protection to require the + # individual matrix job names instead.) Linux-UI: name: Linux-UI - needs: [ build-linux, discover-plans, e2e-linux ] + needs: [ lint, build, discover-plans, e2e ] if: ${{ always() }} runs-on: ubuntu-latest steps: - - name: Verify Linux jobs + - name: Verify upstream jobs shell: bash run: | - echo "build-linux: ${{ needs.build-linux.result }}" + echo "lint: ${{ needs.lint.result }}" + echo "build: ${{ needs.build.result }}" echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e-linux: ${{ needs.e2e-linux.result }}" - if [ "${{ needs.build-linux.result }}" != "success" ] || \ + echo "e2e: ${{ needs.e2e.result }}" + if [ "${{ needs.lint.result }}" != "success" ] || \ + [ "${{ needs.build.result }}" != "success" ] || \ [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e-linux.result }}" != "success" ]; then - echo "::error::One or more Linux-UI jobs failed" + [ "${{ needs.e2e.result }}" != "success" ]; then + echo "::error::One or more required jobs failed" exit 1 fi Windows-UI: name: Windows-UI - needs: [ build-windows, discover-plans, e2e-windows ] + needs: [ lint, build, discover-plans, e2e ] if: ${{ always() }} runs-on: ubuntu-latest steps: - - name: Verify Windows jobs + - name: Verify upstream jobs shell: bash run: | - echo "build-windows: ${{ needs.build-windows.result }}" - echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e-windows: ${{ needs.e2e-windows.result }}" - if [ "${{ needs.build-windows.result }}" != "success" ] || \ + echo "lint: ${{ needs.lint.result }}" + echo "build: ${{ needs.build.result }}" + echo "discover-plans: ${{ needs.discover-plans.result }}" + echo "e2e: ${{ needs.e2e.result }}" + if [ "${{ needs.lint.result }}" != "success" ] || \ + [ "${{ needs.build.result }}" != "success" ] || \ [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e-windows.result }}" != "success" ]; then - echo "::error::One or more Windows-UI jobs failed" + [ "${{ needs.e2e.result }}" != "success" ]; then + echo "::error::One or more required jobs failed" exit 1 fi From 692c93e2118cff057b48e028669d779e45c0530c Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Fri, 5 Jun 2026 11:19:10 +0800 Subject: [PATCH 5/6] ci(e2e): drop redundant Linux-UI / Windows-UI gate jobs Each matrix cell already surfaces as its own PR check, so a separate gate is unnecessary. Branch protection should be updated to require the individual matrix checks (or the 'E2E Summary' job) directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2eUI.yml | 54 ++----------------------------------- 1 file changed, 2 insertions(+), 52 deletions(-) diff --git a/.github/workflows/e2eUI.yml b/.github/workflows/e2eUI.yml index 0eb5bb6e..caa7b962 100644 --- a/.github/workflows/e2eUI.yml +++ b/.github/workflows/e2eUI.yml @@ -13,12 +13,11 @@ on: # build (matrix) → produces one VSIX per OS, uploaded as artifact # e2e (matrix) → cartesian product of {os × plan}, all running in parallel # analyze → aggregates results from BOTH OSes into one unified summary -# Linux-UI → branch-protection gate (preserves required-check name) -# Windows-UI → branch-protection gate (preserves required-check name) # # Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml; matrix # has been extended with an `os` dimension so a single `e2e` job covers both -# platforms. +# platforms. Each matrix cell surfaces as its own PR check, so failures are +# visible without an extra gate job. jobs: # ── Lint + Checkstyle (OS-agnostic) ───────────────────── @@ -254,52 +253,3 @@ jobs: name: e2e-aggregate-summary path: test-results/summary.md retention-days: 30 - - # ── Branch-protection compatibility gates ─────────────── - # Preserve the historical required-status-check names so existing - # branch-protection rules keep working without edits. The matrix - # aggregates per-OS results into a single `needs.e2e.result`, so - # both gates reflect the same overall e2e outcome. (If you want - # truly per-OS gates, switch branch protection to require the - # individual matrix job names instead.) - Linux-UI: - name: Linux-UI - needs: [ lint, build, discover-plans, e2e ] - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Verify upstream jobs - shell: bash - run: | - echo "lint: ${{ needs.lint.result }}" - echo "build: ${{ needs.build.result }}" - echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e: ${{ needs.e2e.result }}" - if [ "${{ needs.lint.result }}" != "success" ] || \ - [ "${{ needs.build.result }}" != "success" ] || \ - [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e.result }}" != "success" ]; then - echo "::error::One or more required jobs failed" - exit 1 - fi - - Windows-UI: - name: Windows-UI - needs: [ lint, build, discover-plans, e2e ] - if: ${{ always() }} - runs-on: ubuntu-latest - steps: - - name: Verify upstream jobs - shell: bash - run: | - echo "lint: ${{ needs.lint.result }}" - echo "build: ${{ needs.build.result }}" - echo "discover-plans: ${{ needs.discover-plans.result }}" - echo "e2e: ${{ needs.e2e.result }}" - if [ "${{ needs.lint.result }}" != "success" ] || \ - [ "${{ needs.build.result }}" != "success" ] || \ - [ "${{ needs.discover-plans.result }}" != "success" ] || \ - [ "${{ needs.e2e.result }}" != "success" ]; then - echo "::error::One or more required jobs failed" - exit 1 - fi From a06aade2b55adc25ee397731ef9aa91828f3c060 Mon Sep 17 00:00:00 2001 From: wenyutang-ms Date: Fri, 5 Jun 2026 13:51:09 +0800 Subject: [PATCH 6/6] ci(e2e): split e2e back into per-OS pipelines for true parallelism Folding OS into the e2e matrix forced every cell to wait for the entire build matrix to finish (Linux + Windows), so a slow Windows build delayed Linux e2e jobs by ~2.5 min unnecessarily (Copilot review feedback). Split back into independent per-OS pipelines: build-linux -> e2e-linux (matrix on plan) build-windows -> e2e-windows (matrix on plan) Both pipelines feed into the shared discover-plans + analyze jobs, so the unified entry point and combined summary are preserved. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/e2eUI.yml | 148 +++++++++++++++++++++++++++--------- 1 file changed, 112 insertions(+), 36 deletions(-) diff --git a/.github/workflows/e2eUI.yml b/.github/workflows/e2eUI.yml index caa7b962..96855ee7 100644 --- a/.github/workflows/e2eUI.yml +++ b/.github/workflows/e2eUI.yml @@ -6,18 +6,24 @@ on: pull_request: branches: [ main ] -# Unified parallel E2E UI pipeline for Linux + Windows. +# Split-pipeline E2E UI workflow. # # lint → tslint + checkstyle (ubuntu, OS-agnostic) # discover-plans → emits a matrix of test-plan basenames -# build (matrix) → produces one VSIX per OS, uploaded as artifact -# e2e (matrix) → cartesian product of {os × plan}, all running in parallel -# analyze → aggregates results from BOTH OSes into one unified summary # -# Modelled after vscode-java-pack/.github/workflows/e2e-autotest.yml; matrix -# has been extended with an `os` dimension so a single `e2e` job covers both -# platforms. Each matrix cell surfaces as its own PR check, so failures are -# visible without an extra gate job. +# build-linux ─┐ +# e2e-linux (×plan) ┤ +# ├──→ analyze → unified summary covering both OSes +# build-windows ─┤ +# e2e-windows (×plan)┘ +# +# Per-OS pipelines run completely independently: Linux e2e jobs do NOT +# wait for the Windows VSIX build (and vice versa), so a slow Windows +# build cannot delay the start of Linux e2e plans. Each matrix cell +# surfaces as its own PR check, so failures are visible without an +# extra gate job. +# +# Inspired by vscode-java-pack/.github/workflows/e2e-autotest.yml. jobs: # ── Lint + Checkstyle (OS-agnostic) ───────────────────── @@ -66,15 +72,11 @@ jobs: echo "matrix=$plans" >> "$GITHUB_OUTPUT" echo "Found plans: $plans" - # ── Build VSIX (one per OS) ───────────────────────────── - build: - name: Build VSIX (${{ matrix.os }}) - runs-on: ${{ matrix.os }} + # ── Build VSIX (Linux) ────────────────────────────────── + build-linux: + name: Build VSIX (Linux) + runs-on: ubuntu-latest timeout-minutes: 20 - strategy: - fail-fast: false - matrix: - os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 @@ -104,27 +106,63 @@ jobs: - name: Upload VSIX artifact uses: actions/upload-artifact@v4 with: - name: vsix-${{ matrix.os }} + name: vsix-linux path: vscode-java-dependency.vsix retention-days: 1 - # ── Run every (OS × plan) combo in parallel ───────────── - e2e: - name: E2E (${{ matrix.os }} / ${{ matrix.plan }}) - needs: [ build, discover-plans ] - runs-on: ${{ matrix.os }} + # ── Build VSIX (Windows) ──────────────────────────────── + build-windows: + name: Build VSIX (Windows) + runs-on: windows-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install Node.js modules + run: npm install + + - name: Install VSCE + run: npm install -g @vscode/vsce + + - name: Build OSGi bundle + run: npm run build-server + + - name: Build VSIX file + run: vsce package -o vscode-java-dependency.vsix + + - name: Upload VSIX artifact + uses: actions/upload-artifact@v4 + with: + name: vsix-windows + path: vscode-java-dependency.vsix + retention-days: 1 + + # ── E2E plans (Linux) — depends only on Linux build ───── + e2e-linux: + name: E2E Linux (${{ matrix.plan }}) + needs: [ build-linux, discover-plans ] + runs-on: ubuntu-latest timeout-minutes: 25 strategy: fail-fast: false matrix: - os: [ ubuntu-latest, windows-latest ] plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} steps: - uses: actions/checkout@v4 - - name: Setup Linux Build Environment (Xvfb) - if: runner.os == 'Linux' + - name: Setup Build Environment (Xvfb) run: | sudo apt-get update sudo apt-get install -y libxkbfile-dev pkg-config libsecret-1-dev libxss1 dbus xvfb libgtk-3-0 libgbm1 @@ -151,11 +189,10 @@ jobs: - name: Download VSIX artifact uses: actions/download-artifact@v4 with: - name: vsix-${{ matrix.os }} + name: vsix-linux path: . - - name: E2E Test — ${{ matrix.plan }} (Linux) - if: runner.os == 'Linux' + - name: E2E Test — ${{ matrix.plan }} shell: bash env: AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} @@ -166,8 +203,49 @@ jobs: --vsix "$(pwd)/vscode-java-dependency.vsix" \ --output "test-results/${{ matrix.plan }}" - - name: E2E Test — ${{ matrix.plan }} (Windows) - if: runner.os == 'Windows' + - name: Upload test results + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: e2e-results-linux-${{ matrix.plan }} + path: test-results/ + retention-days: 7 + + # ── E2E plans (Windows) — depends only on Windows build ─ + e2e-windows: + name: E2E Windows (${{ matrix.plan }}) + needs: [ build-windows, discover-plans ] + runs-on: windows-latest + timeout-minutes: 25 + strategy: + fail-fast: false + matrix: + plan: ${{ fromJson(needs.discover-plans.outputs.matrix) }} + + steps: + - uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + java-version: '21' + distribution: 'temurin' + + - name: Setup Node.js environment + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Setup autotest + run: npm install -g @vscjava/vscode-autotest + + - name: Download VSIX artifact + uses: actions/download-artifact@v4 + with: + name: vsix-windows + path: . + + - name: E2E Test — ${{ matrix.plan }} shell: pwsh env: AZURE_OPENAI_ENDPOINT: ${{ secrets.AZURE_OPENAI_ENDPOINT }} @@ -180,14 +258,14 @@ jobs: if: ${{ always() }} uses: actions/upload-artifact@v4 with: - name: e2e-results-${{ matrix.os }}-${{ matrix.plan }} + name: e2e-results-windows-${{ matrix.plan }} path: test-results/ retention-days: 7 # ── Unified analysis across both OSes ─────────────────── analyze: name: E2E Summary - needs: e2e + needs: [ e2e-linux, e2e-windows ] if: ${{ always() }} runs-on: ubuntu-latest steps: @@ -210,9 +288,7 @@ jobs: shell: bash run: | mkdir -p test-results - # Artifact dir names look like: e2e-results-ubuntu-latest- - # or e2e-results-windows-latest- - for dir in all-results/e2e-results-ubuntu-latest-*/; do + for dir in all-results/e2e-results-linux-*/; do [ -d "$dir" ] || continue find "$dir" -name "results.json" -exec dirname {} \; | while read d; do name=$(basename "$d") @@ -220,7 +296,7 @@ jobs: cp -r "$d"/. "test-results/linux-$name"/ done done - for dir in all-results/e2e-results-windows-latest-*/; do + for dir in all-results/e2e-results-windows-*/; do [ -d "$dir" ] || continue find "$dir" -name "results.json" -exec dirname {} \; | while read d; do name=$(basename "$d")