Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: 🐛 Bug report
description: Report a bug in Project Manager for Java, with a reproducible project so it can be confirmed automatically.
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for filing a bug! A **minimal reproducible project** lets a maintainer (or the Copilot agent) reproduce the issue with an AutoTest UI test and turn it into a regression test. The more precise the repro, the faster the fix.

- type: textarea
id: description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
validations:
required: true

- type: input
id: repro-project
attributes:
label: Reproducible project
description: A link to a public GitHub repo, or note that you attached a zip below. Prefer the smallest project that still shows the bug.
placeholder: "https://github.com/<you>/<minimal-repro>"
validations:
required: true

- type: textarea
id: steps
attributes:
label: Steps to reproduce
description: Exact steps against the project above. Name the affected surface (Java Projects tree, a context-menu / command, Referenced Libraries, export jar, new type, etc.).
placeholder: |
1. Open the project above in VS Code
2. Focus the Java Projects view
3. Expand src/main/java > com.example
4. Right-click App.java > ...
validations:
required: true

- type: textarea
id: expected
attributes:
label: Expected behavior
validations:
required: true

- type: textarea
id: actual
attributes:
label: Actual behavior
description: What happened instead. Screenshots and the "Java" / "Language Support for Java" output-channel logs help a lot.
validations:
required: true

- type: textarea
id: versions
attributes:
label: Environment
description: Fill in the versions you are running.
value: |
- OS:
- VS Code version:
- Extension Pack for Java / Project Manager for Java version:
- JDK version:
validations:
required: true
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
blank_issues_enabled: true
contact_links:
- name: 💬 Questions & discussions
url: https://github.com/microsoft/vscode-java-dependency/discussions
about: Ask usage questions or start a discussion instead of filing a bug.
13 changes: 12 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
# Copilot instructions for vscode-java-dependency

## Bug reproduction

- **Classify the task first — the repro / UI-test flow is opt-in, not automatic.** Use the `repro` skill **only** when the task is to fix or confirm a **reproducible bug** (an issue that carries repro steps + a project, or you are explicitly asked to reproduce/confirm a report). For everything else — new features, refactors, performance work, dependency/version bumps, docs, config, CI, or code cleanup — make a normal PR with the appropriate unit/integration tests and **do not** author a `test/e2e-plans/repro-issue-*.yaml`. No repro plan file means the CI red→green gate never triggers; nothing extra runs.
- **What always runs vs what is opt-in:** every PR to `main` still gets lint + the existing `java-dep-*` regression E2E (unchanged safety net). The red→green **gate is additional and fires only when the PR contains a `repro-issue-<n>.yaml`.** So the decision to enter this flow is made purely by whether you commit a repro plan. The gate is an **independent re-run and the execution surface for OS-specific plans** — your own run in the agent environment is the primary proof.
- If a report is **not reproducible** (vague, missing project, environment- or hardware-specific, depends on an external service), do **not** force a reproduction or invent a plan: ask for a minimal repro and label `needs-more-info`, or fix with the best available non-UI test and say so.
- When you have decided the task **is** a reproducible bug: first decide whether it needs a UI/E2E test. Use an AutoTest plan (`uitest` skill) for user-facing surfaces (Java Projects tree, context menus, commands, classpath, export jar, view modes). Use a `test/maven-suite` unit test or a `jdtls.ext` test for pure logic, backend, or build/packaging bugs.
- Reproduce with the reporter's project: clone the linked repo as a sibling or recreate the zip/inline sources, then distill it to a **minimal committed fixture**. Do not commit whole user projects or large binaries.
- **Prove the red→green in your own environment first — CI is a fallback, not a requirement.** Run the plan/test yourself: red on the un-fixed build, green after the fix, **iterating until you observe green** (crash/error = flaky, re-run; assertion-`fail` = fix wrong/incomplete, read `results.json` and iterate). Leave it committed as a regression test (`test/e2e-plans/repro-issue-<n>.yaml` is picked up by CI automatically), and commit the repro plan and the fix **together in one PR**. For an **OS-specific** bug your agent OS cannot reproduce (e.g. a Windows-only bug on a Linux agent), name the plan `repro-issue-<n>-windows.yaml` / `-linux.yaml` and let CI's red→green gate run it on that OS; read the result back with `gh run watch` / `gh run download` and iterate.
- If no reproducible project is provided and the bug is environment-specific, ask for one and label `needs-more-info` — do not fabricate a fix for an unreproduced bug.

## UI and E2E tests

- When asked to add, update, run, or debug UI/E2E coverage, prefer the AutoTest YAML workflow under `test/e2e-plans/`.
- Use the `uitest` skill for UI test work. It should create or update `test/e2e-plans/*.yaml`, validate the plan, build the OSGi bundle and package the extension when needed, run AutoTest, and inspect `test-results/`.
- Do not create legacy VS Code extension tests (`test/maven-suite`, `test/gui`) for UI coverage unless the user explicitly asks for that format.
- Prefer deterministic AutoTest verifiers (`verifyTreeItem`, `verifyFile`, `verifyEditorTab`, `verifyClipboard`) over screenshot-only checks.
- Prefer deterministic AutoTest verifiers (`verifyTreeItem`, `verifyFile`, `verifyEditorTab`, `verifyClipboard`) on the decisive assertion step; you do not need a verifier on every step. Screenshots prove a fix (a red run before, a green run after) — but never as the sole pass/fail authority for the decisive assertion.
- **Evidence: textual self-run proof + CI-hosted screenshots; never commit binaries.** Raw `test-results/` is git-ignored and screenshots are **never committed to the repo**. For a self-run repro, prove red→green as text on the issue/PR: the decisive failing step and the **actual observed value** from the red run's `results.json`, then the green result. `.github/workflows/e2eUI.yml` runs each `test/e2e-plans/*.yaml` on Linux + Windows and uploads full `test-results/` (screenshots + `results.json`) as artifacts; for a `repro-issue-<n>.yaml` an OS-aware **red→green gate** rebuilds the PR base and runs the plan against base **and** head on the OS(es) the suffix implies, requiring `base ❌ RED → head ✅ GREEN` (`repro-gate-results-<os>-<plan>` artifacts) — link those for the images and for an OS-specific plan you could not run yourself; ordinary regression plans upload `e2e-results-<os>-<plan>`. A maintainer can drag an artifact PNG into a comment for an inline view (`user-images.githubusercontent.com`), still outside git.
7 changes: 4 additions & 3 deletions .github/instructions/uitest-plan.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Test plans under `test/e2e-plans/` are executable YAML files consumed by `@vscja

## Setup rules

- Use `setup.extension: "vscjava.vscode-java-pack"` plus `setup.vscodeVersion: "stable"` for most scenarios. Installing the Extension Pack for Java pulls in every Java extension the Java Projects view relies on, so there is no need to install `redhat.java` separately.
- Use `setup.extension: "vscjava.vscode-java-pack"` plus `setup.vscodeVersion: "stable"` for most scenarios. Installing the Extension Pack for Java pulls in every Java extension the Java Projects view relies on, so there is no need to install `redhat.java` separately. Keep `stable` (always the latest release) — do **not** pin a concrete version. In the Copilot agent, `.github/workflows/copilot-setup-steps.yml` pre-downloads that latest build + the pack before the firewall, and `@vscode/test-electron` falls back to the cached build when the run-time version check is blocked, so the plan runs offline without pinning.
- Install the extension under test from a local VSIX at runtime with `--vsix vscode-java-dependency.vsix` — do not rely on a marketplace copy of `vscjava.vscode-java-dependency`.
- Use existing in-repo fixtures as the workspace: `../maven` (a `maven-archetype-quickstart` project: `my-app` / `com.mycompany.app` / `App.java`) or `../invisible` (an unmanaged-folder project for referenced-library scenarios). Paths are relative to the test plan file. Do not add large binary fixtures.
- Referenced-library / classpath commands (`java.project.addLibraries`, `java.project.removeLibrary`, `java.project.addLibraryFolders`, `java.project.refreshLibraries`) only apply to invisible projects — use `../invisible`, not `../maven`, for those.
Expand All @@ -31,12 +31,13 @@ action: 'clickViewTitleAction "Java Projects" "Unlink with Editor"'

## Verification rules

- Add deterministic verification to every meaningful step. The natural-language `verify` field is context for humans and failure analysis; it is not pass/fail authority by itself, and it is auto-passed when a plan runs with `--no-llm`.
- You do **not** need a verifier on every step. Author the *actions* step-by-step, but gate pass/fail with a deterministic verifier only on the **decisive assertion step(s)** — the step that captures the reported bug — plus any step prone to a silent no-op (see the `expandTreeItem` / free-form action caveat above). Intermediate action steps can rely on AutoTest screenshots instead of their own verifier.
- The natural-language `verify` field is context for humans and failure analysis; it is not pass/fail authority by itself, and it is auto-passed when a plan runs with `--no-llm`. So the decisive step **must** carry a deterministic verifier, or a `--no-llm` run is a false green.
- Use `verifyTreeItem` (with `name:`, optional `exact: true`, and `visible: false` for absence) as the authoritative check for Java Projects tree state.
- Use `verifyFile` after operations that create, modify, or delete files on disk (new type, export jar, permanent delete). VS Code can open duplicate editor tabs with stale buffers, so prefer file-content checks over editor checks after such operations.
- Use `verifyEditorTab` to assert which file an action opened, and `verifyClipboard` for copy-path commands.
- On state-check steps whose only assertion is a deterministic verifier, omit the `verify:` field to avoid false LLM failures.
- Use screenshots only as diagnostics produced by AutoTest; do not make screenshots the only evidence of pass/fail.
- Screenshots are AutoTest's evidence that an action ran and are the primary artifact for **proving a fix** (a red run before, a green run after). Do not make a screenshot the sole pass/fail authority for the decisive assertion — pair it with a deterministic verifier.

## Local validation commands

Expand Down
95 changes: 95 additions & 0 deletions .github/scripts/prewarm-vscode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env node
/*
* Pre-download VS Code + the Java extensions into AutoTest's cache BEFORE the
* Copilot coding agent's firewall is enabled.
*
* AutoTest (`@vscjava/vscode-autotest`) launches VS Code via `@vscode/test-electron`:
* 1. downloadAndUnzipVSCode(version) -> <cwd>/.vscode-test/vscode-<...>
* 2. resolveCliArgsFromVSCodeExecutablePath() -> --extensions-dir=<cwd>/.vscode-test/extensions
* 3. code --install-extension <id> --force -> pulls Marketplace bits into that extensions dir
*
* The VS Code CDN (update.code.visualstudio.com) and the Marketplace are NOT on the
* Copilot agent's default firewall allowlist, so those network calls fail at run time.
* This script performs the exact same three operations during `copilot-setup-steps`
* (which runs before the firewall), so the caches are warm and the firewalled UI run
* hits them offline.
*
* Because `@vscode/test-electron` derives its cache from `process.cwd()`, this MUST run
* from the repository root — the same directory AutoTest runs from at agent time.
*
* Env overrides:
* VSCODE_VERSION VS Code channel/version to warm (default: "stable")
* PREWARM_EXTENSIONS comma-separated extension ids (default: "vscjava.vscode-java-pack")
*/
"use strict";

const path = require("path");
const cp = require("child_process");

function resolveTestElectron() {
// Prefer the exact copy that the globally installed AutoTest uses, so the
// version and default-cache-path logic match the agent run byte-for-byte.
const candidates = [];
try {
const globalRoot = cp.execSync("npm root -g", { encoding: "utf-8" }).trim();
candidates.push(path.join(globalRoot, "@vscjava", "vscode-autotest"));
candidates.push(globalRoot);
} catch {
/* npm not on PATH — fall back to local resolution below */
}
candidates.push(process.cwd());
try {
const entry = require.resolve("@vscode/test-electron", { paths: candidates });
return require(entry);
} catch {
// Last resort: a plain require (works if it is a local dependency).
return require("@vscode/test-electron");
}
}

async function main() {
const version = process.env.VSCODE_VERSION || "stable";
const extensions = (process.env.PREWARM_EXTENSIONS || "vscjava.vscode-java-pack")
.split(",")
.map((s) => s.trim())
.filter(Boolean);

const { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath } = resolveTestElectron();

console.log(`⬇️ Pre-downloading VS Code "${version}" into ${path.join(process.cwd(), ".vscode-test")} ...`);
const vscodePath = await downloadAndUnzipVSCode(version);
console.log(`✅ VS Code ready: ${vscodePath}`);

const [cli, ...baseArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodePath);
const extensionsDir = baseArgs.find((a) => a.startsWith("--extensions-dir="))?.split("=")[1];
console.log(`📁 Extensions dir: ${extensionsDir ?? "(default)"}`);

let failures = 0;
for (const ext of extensions) {
console.log(`📦 Installing ${ext} (+ Extension Pack members) ...`);
try {
cp.execFileSync(cli, [...baseArgs, "--install-extension", ext, "--force"], {
stdio: "inherit",
timeout: 300_000,
env: { ...process.env },
shell: process.platform === "win32",
});
console.log(`✅ Installed ${ext}`);
} catch (e) {
failures++;
console.warn(`⚠️ Failed to install ${ext}: ${e.message}`);
}
}

if (failures > 0) {
// Non-fatal: a missing extension only degrades UI reproduction, and the agent
// can still fall back to the non-UI path. Surface it without aborting setup.
console.warn(`⚠️ ${failures} extension(s) failed to pre-install; UI reproduction may be degraded.`);
}
console.log("🎉 VS Code + Java extensions pre-warmed for AutoTest.");
}

main().catch((err) => {
console.error("❌ Pre-warm failed:", err);
process.exit(1);
});
Loading
Loading