Skip to content

feat(python-setup): add "Install uv" button to the uv-missing error - #2113

Merged
rugpanov merged 6 commits into
mainfrom
python-setup-install-uv-button
Aug 14, 2026
Merged

feat(python-setup): add "Install uv" button to the uv-missing error#2113
rugpanov merged 6 commits into
mainfrom
python-setup-install-uv-button

Conversation

@rugpanov

Copy link
Copy Markdown
Contributor

Why

When environments setup-local fails because uv is not installed (E_UV_MISSING), the error popup only offered Show Logs, leaving the user to find and install uv on their own. This adds a one-click path to uv's install guide, matching how the extension already surfaces the Azure CLI install instructions.

What

The popup now shows [Install uv] [Show Logs] on E_UV_MISSING. Clicking Install uv opens uv's official install page (https://docs.astral.sh/uv/getting-started/installation/) via the existing openExternal helper — it deliberately links to the docs (which pick the right installer per platform) rather than running an installer itself. Every other failure code is unchanged (Show Logs only).

  • errorMessages.ts: single-source UV_INSTALL_DOCS_URL and a small getPythonSetupErrorAction(result) helper returning a {label, url} action only for E_UV_MISSING, so the call-to-action lives next to the message copy.
  • PythonSetupEnvironmentSetup.ts: showError gains an optional action arg; the failure path passes getPythonSetupErrorAction(result).
  • pythonSetupDeps.ts: render the remediation button first (before Show Logs) and open its URL when picked.

The action param is optional, so the other showError call sites are unchanged.

Verification

  • TDD: 5 new unit tests (action mapping; deps button shown + URL opened on pick, not opened otherwise; orchestrator passes the action on uv-missing and none on other failures).
  • yarn test:unit — 739 passing, 0 failing.
  • tsc --noEmit clean; yarn test:lint + Prettier clean.

This pull request and its description were written by Isaac.

*Why*
When `environments setup-local` fails because uv is not installed
(`E_UV_MISSING`), the error popup only offered "Show Logs", leaving the
user to find and install uv on their own. Give them a one-click path to
uv's install guide, matching how the extension already surfaces the
Azure CLI install instructions.

*What*
- errorMessages.ts: single-source `UV_INSTALL_DOCS_URL` and a small
  `getPythonSetupErrorAction(result)` helper that returns an
  {label, url} action only for `E_UV_MISSING`, so the call-to-action
  lives next to the message copy.
- PythonSetupEnvironmentSetup.ts: `showError` gains an optional `action`
  arg; the failure path passes `getPythonSetupErrorAction(result)`.
- pythonSetupDeps.ts: render the remediation button first (before
  "Show Logs") and open its URL via the existing `openExternal` helper
  when picked. Deliberately links to the docs (which pick the right
  installer per platform) rather than running an installer itself.

The `action` param is optional, so the other `showError` call sites are
unchanged and keep their Show-Logs-only popup.

*Verification*
- TDD: 5 new unit tests (errorMessages action mapping; deps button shown
  + URL opened on pick, not opened otherwise; orchestrator passes the
  action on uv-missing and none on other failures).
- yarn test:unit — 739 passing, 0 failing.
- tsc --noEmit clean; yarn test:lint + Prettier clean.

Co-authored-by: Isaac
@rugpanov

rugpanov commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ❌ 3 of 4 test jobs failed for 6403b8dd (0 passed, 1 skipped).
View run

…s label

*Why*
Code review (Isaac + Codex + Claude) independently flagged that
`showErrorMessage` returns the picked button as a bare label string, so
two buttons sharing a label are indistinguishable. If a future
`PythonSetupErrorAction` ever used the reserved "Show Logs" label, its
URL branch would be dead code and the click would show the log instead.
Harmless today (the only action is "Install uv") but worth guarding.

*What*
- pythonSetupDeps.ts: ignore an action whose label equals the reserved
  "Show Logs" (offer the single unambiguous Show Logs button instead of
  a colliding pair), and dispatch on that guarded `remediation`.

*Verification*
- TDD: new unit test asserts a colliding "Show Logs" action yields only
  one button and never opens the URL.
- yarn test:unit — 740 passing, 0 failing.
- tsc --noEmit clean; yarn test:lint + Prettier clean.

Co-authored-by: Isaac
@rugpanov

rugpanov commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ❌ 3 of 4 test jobs failed for 1dd9bddc (0 passed, 1 skipped).
View run

*Why*
Review flagged that showError is the failure-reporting path and its sole
caller (PythonSetupEnvironmentSetup.setup) does not wrap it, so a
rejecting `env.openExternal` when the user clicks "Install uv" would
reject the whole setup flow — an unhandled rejection in the error path.

*What*
- pythonSetupDeps.ts: wrap the `openExternal(remediation.url)` call in
  try/catch; on failure append the error to the log channel instead of
  letting the popup reject.

*Verification*
- TDD: new unit test stubs `env.openExternal` to throw and asserts
  showError resolves and records the failure to the log.
- yarn test:unit — 741 passing, 0 failing.
- tsc --noEmit clean; yarn test:lint + Prettier clean.

Co-authored-by: Isaac
@rugpanov

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests triggered for b842e04c — ⏳ running.
View run

*Why*
Iteration-2 review (Codex + Claude + Isaac) noted showError's "Install uv"
handler only caught a rejected launch: `env.openExternal` can instead
*resolve false* when VS Code cannot open the URI, which was silently
ignored despite the comment promising to record it. Two smaller nits:
a non-Error throw logged "undefined", and the button-order intent was
asserted with `.contain` (order not actually verified).

*What*
- urlUtils.ts: `openExternal` now forwards VS Code's boolean result
  (Promise<boolean>) so callers can observe a false "could not open".
- pythonSetupDeps.ts: log both a false result and a thrown error; use
  `e instanceof Error ? e.message : String(e)` for the thrown case.
- pythonSetupDeps.test.ts: add a resolves-false case; tighten the
  button-order assertion to deep.equal(["Install uv","Show Logs"]).

*Verification*
- TDD: new false-resolve test (RED against the old catch-only code);
  ordering assertion tightened.
- yarn test:unit — 742 passing, 0 failing.
- tsc --noEmit clean; yarn test:lint + Prettier clean.

Co-authored-by: Isaac
@rugpanov

rugpanov commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ❌ 3 of 4 test jobs failed for 985578a7 (0 passed, 1 skipped).
View run

…uv-button

# Conflicts:
#	packages/databricks-vscode/src/python-setup/controllers/PythonSetupEnvironmentSetup.ts
@rugpanov
rugpanov deployed to test-trigger-is August 14, 2026 08:47 — with GitHub Actions Active
@rugpanov
rugpanov deployed to test-trigger-is August 14, 2026 08:47 — with GitHub Actions Active
@rugpanov

rugpanov commented Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ❌ 1 of 35 test jobs failed for 3b5067e3 (34 passed).
View run

@rugpanov
rugpanov deployed to test-trigger-is August 14, 2026 11:03 — with GitHub Actions Active
@rugpanov
rugpanov deployed to test-trigger-is August 14, 2026 11:03 — with GitHub Actions Active
@github-actions

Copy link
Copy Markdown
Contributor

If integration tests don't run automatically, an authorized user can run them manually by following the instructions below:

Trigger:
go/deco-tests-run/vscode

Inputs:

  • PR number: 2113
  • Commit SHA: 2c07b794514fafe94567f32f7b4fc12a7541d9d2

Checks will be approved automatically on success.

@rugpanov
rugpanov merged commit f3784e1 into main Aug 14, 2026
7 of 9 checks passed
rugpanov added a commit that referenced this pull request Aug 14, 2026
…unreachable (#2116)

## Why

On locked-down corporate machines `pypi.org` is blocked and uv must
reach an alternate index/proxy. When it can't, `environments
setup-local` fails as `E_PROVISION` and the extension showed a
misleading **"dependency version conflict"** message — leaving users
with no path forward.

## What

- **Detect** uv's package-index connectivity failures and surface
tailored guidance:
  - a popup naming `UV_INDEX_URL` / a pip.conf `index-url`,
  - a **Configure package index** button linking uv's index docs,
- a copy-pasteable remediation block in the output channel (the raw CLI
error is still shown).
- **Scope precisely**: `E_PROVISION` only, requiring uv's `failed to
fetch` index context (excluding git deps) **plus** a host-unreachable
symptom — so genuine dependency conflicts, git-dependency fetches, and
build-tool stderr are not mislabelled. `E_PYTHON_INSTALL` is
deliberately excluded (a managed-CPython download from a different
mirror that this guidance can't fix).
- **Telemetry**: an optional boolean `indexUnreachable` on
`python_env.setup.result` to measure how often a blocked index (vs a
conflict) is the cause.

## Verification

- `yarn test:unit` — 757 passing, 0 failing (detector, message, action,
output-channel remediation, telemetry, and negative cases).
- prettier + eslint clean.
- Reproduced against **real uv 0.12.3** output (`UV_INDEX_URL` → a
refusing endpoint): the genuine `Failed to fetch … Connection refused`
text maps to the proxy guidance and button.

## Note

Stacks on #2113 (the "Install uv" button), which introduces the popup
action-button infra this builds on. The diff shows those commits too
until #2113 merges; please merge this after #2113.

This pull request and its description were written by Isaac.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants