Skip to content

feat(python-setup): narrate live progress during environment setup - #2139

Merged
rugpanov merged 5 commits into
mainfrom
feat-python-setup-progress
Aug 21, 2026
Merged

feat(python-setup): narrate live progress during environment setup#2139
rugpanov merged 5 commits into
mainfrom
feat-python-setup-progress

Conversation

@rugpanov

@rugpanov rugpanov commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Problem

The uv Setting up Python environment run shows a mute, indeterminate spinner for a minute or more. Under --output json the CLI streams no progress — it buffers everything and prints a single result object at the end — so the notification sat silent, with no sign it was alive or how long it had been running.

Change

Add python-setup/utils/setupProgress.ts, a pure module that turns the one hard fact we have during the run — elapsed time — into an honest, informative progress line:

  • Walks the fast leading phases in order (3.5 s each), mirroring the CLI's own spinner labels: checking prerequisites…, resolving your Databricks compute…, fetching matching versions and constraints…, updating pyproject.toml….
  • Then dwells on the dominant provision phase, rotating its real uv sub-steps (6 s each, looping): installing the matching Python version…, creating the virtual environment…, resolving the dependency graph…, downloading databricks-connect and dependencies…, building and installing packages with uv…, syncing your project's dependencies….
  • Appends an m:ss elapsed counter, updated once a second.

It never shows a percentage and never claims a phase finished — without a live signal from the CLI that can't be observed, so the copy stays truthful (real work, real order, estimated timing).

The ticker lives in withElapsedProgress (timer/clock injected so it's unit-testable, and the work deferred so a synchronous throw still clears the interval). The withProgress wiring in pythonSetupDeps.ts calls it. The orchestrator and CLI client are untouched — no new CLI args, no --output json change.

Interim, but not throwaway

This is the extension-only interim. The proper fix is a structured progress stream from the CLI; when that lands, the observed phase feeds this same rendering and the leading-phase time estimate drops away — the elapsed counter and provision rotation stay as the fallback for older bundled CLIs.

Testing

  • Co-located unit tests for the pure module (18 cases): elapsed formatting incl. minute roll-over and negative/non-finite clamp, leading-phase walk, provision rotation and looping, composed message, and withElapsedProgress reporting + interval cleanup on resolve / reject / synchronous throw.
  • tsc -b clean, eslint clean, prettier clean.

This pull request and its description were written by Isaac.

*Why*
The uv "Setting up Python environment" run shows a mute, indeterminate
spinner for a minute or more. Under `--output json` the CLI streams no
progress — it buffers everything and prints one result object at the end —
so the notification sat silent with no sign it was alive or how long it
had been going.

*What*
Add `utils/setupProgress.ts`: a pure module that turns elapsed time into an
honest progress line. It narrates the real, ordered work `setup-local`
performs — the fast leading phases (mirroring the CLI's own spinner labels),
then the dominant provision phase's real uv sub-steps, rotating — with an
`m:ss` elapsed counter. It never shows a percentage and never claims a phase
finished, since without a live signal that can't be observed. Wire the
previously-ignored progress reporter in `pythonSetupDeps.ts` to tick this
once a second and stop when the work settles. The orchestrator and CLI client
are untouched (no new args). When the CLI grows a structured progress stream,
the observed phase feeds this same rendering; the counter and rotation remain
the fallback.

*Verification*
- New co-located unit tests for the pure module (11 cases): elapsed
  formatting incl. minute roll-over and negative clamp, leading-phase walk,
  provision rotation and looping, composed message. All pass via ts-mocha.
- `tsc -b` clean; eslint clean; prettier clean.

Co-authored-by: Isaac <no-reply@databricks.com>
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 08:17 — with GitHub Actions Active
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 08:17 — with GitHub Actions Active
@rugpanov

rugpanov commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ✅ all 41 test jobs passed for cf1d0e67.
View run

rugpanov and others added 2 commits August 21, 2026 11:30
*Why*
Review of the progress-narration change surfaced two real issues: the
interval was started before `.finally` was attached, so a *synchronous*
throw from the task (e.g. argv building in the CLI client runs outside its
promise) would leak the ticker forever; and the exported time helpers
returned `NaN:NaN` for non-finite input.

*What*
- Extract the ticker into `withElapsedProgress` (setupProgress.ts): it defers
  the work through `Promise.resolve().then(...)` so a sync throw still routes
  through `finally` and clears the interval. Timer/clock is an injected seam
  so the behavior is unit-testable without the extension host.
- Clamp non-finite (and negative) input to 0 in the elapsed/phase helpers.
- Simplify the `withProgress` wiring in pythonSetupDeps.ts to call it.

*Verification*
- 7 new cases (18 total): non-finite clamp; and withElapsedProgress opening
  report, per-tick re-report, and interval cleanup on resolve / reject /
  synchronous throw. All pass via ts-mocha.
- `tsc -b` clean; eslint clean; prettier clean.

Co-authored-by: Isaac <no-reply@databricks.com>
*Why*
Iterating on how the narration reads in the editor: the leading phases went
by too fast to read, the provision stretch had too few messages for the
minute-plus it runs, and the phrasing was inconsistently capitalized.

*What*
- Show each leading phase for 3.5s (was 1.5s) so it's readable.
- Expand the provision rotation from 3 to 6 real uv sub-steps (install
  Python, create venv, resolve, download, build/install, sync).
- Lowercase the leading letter of every phrase (proper nouns — Databricks,
  Python — stay capitalized).

*Verification*
- Unit tests updated for the new boundaries/phrases; 18 pass via ts-mocha.
- eslint clean; prettier clean.

Co-authored-by: Isaac <no-reply@databricks.com>
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 08:46 — with GitHub Actions Active
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 08:47 — with GitHub Actions Active
@rugpanov
rugpanov marked this pull request as ready for review August 21, 2026 08:50
@rugpanov

rugpanov commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ✅ all 41 test jobs passed for 948e3c21.
View run

*Why*
Delta re-review noted the cleanup assertions could pass vacuously: a test
that only checks `allCleared()` also passes when no interval was ever
started, and the synchronous-throw test discarded the error without
confirming it propagated.

*What*
- Assert `started() === 1` in the resolve and reject cases so cleanup is
  proven against an interval that actually ran.
- Capture the synchronous throw and assert its message is preserved.

*Verification*
- 18 tests pass via ts-mocha; eslint and prettier clean.

Co-authored-by: Isaac <no-reply@databricks.com>
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 11:55 — with GitHub Actions Active
@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 11:55 — with GitHub Actions Active
@rugpanov

rugpanov commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

🤖 Integration tests ❌ 5 of 41 test jobs failed for 70b34665 (36 passed).
View run

@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 13:14 — with GitHub Actions Active
@rugpanov
rugpanov merged commit f606d0a into main Aug 21, 2026
6 checks passed
@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: 2139
  • Commit SHA: d730133c9e9d777d2f092e630cb8268567bd6e2b

Checks will be approved automatically on success.

@rugpanov
rugpanov deployed to test-trigger-is August 21, 2026 13:16 — with GitHub Actions Active
@github-actions github-actions Bot mentioned this pull request Aug 21, 2026
rugpanov added a commit that referenced this pull request Aug 21, 2026
## packages/databricks-vscode
## (2026-08-21)

* Narrate live progress during Python environment setup (#2139)
([f606d0a](f606d0a))
* Pre-check the host CLI before starting the SSH tunnel (#2127)
([5af58f2](5af58f2))
* Show an info toast on a successful Python environment setup that had
warnings (#2138)
([2acdc44](2acdc44))
* Avoid duplicate profile section creation in `.databrickscfg` during
OAuth setup (#2133)
([6e1c472](6e1c472))

## packages/databricks-vscode-types
## (2026-08-21)

---------

Co-authored-by: releasebot <noreply@github.com>
Co-authored-by: Grigory Panov <grigory.panov@databricks.com>
Co-authored-by: Isaac <no-reply@databricks.com>
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