Skip to content

Adopt package manager command classes - #1686

Open
Eduardo Villalpando Mello (edvilme) wants to merge 22 commits into
mainfrom
package-manager-command-adoption
Open

Adopt package manager command classes#1686
Eduardo Villalpando Mello (edvilme) wants to merge 22 commits into
mainfrom
package-manager-command-adoption

Conversation

@edvilme

@edvilme Eduardo Villalpando Mello (edvilme) commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Adopts the package manager command classes introduced in #1621 across Pip/UV, Conda, and Poetry.

Changes

  • Replaces existing command construction and execution paths with the new command classes.
  • Preserves existing command flags, environment targeting, version ordering, prerelease defaults, timeouts, and Poetry cwd behavior.
  • Removes superseded utility wrappers and obsolete tests tied to those utilities.
  • Adds a parametrized package-manager roundtrip integration test (install → list → direct-deps → available-versions → uninstall) driven by the public API and grouped by managerId, so future managers are covered automatically. The available-versions step is capability-guarded so it runs when the API surfaces getPackageAvailableVersions and skips gracefully otherwise.

Relationship

Testing

  • npm run compile-tests
  • npm run unittest (1,475 passing)
  • Roundtrip integration test runs in the extension host via npm run integration-test.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR migrates Pip/UV, Conda, and Poetry package manager call sites to the newer package-manager command class layer (introduced in #1621), and removes older helper utilities/tests that those call sites depended on.

Changes:

  • Replaces ad-hoc command construction/execution with concrete command classes for Pip/UV, Conda, and Poetry.
  • Refactors Pip/Conda/Poetry package manager flows to use command objects (including progress + cancellation wiring).
  • Removes superseded parsing/execution utilities and replaces related unit tests with command-focused tests.

Reviewed changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/test/managers/poetry/commands.unit.test.ts Adds Poetry command smoke tests (currently mostly “does not reject”).
src/test/managers/conda/commands.unit.test.ts Adds Conda command smoke tests (currently mostly “does not reject”).
src/test/managers/builtin/commands.unit.test.ts Adds Pip/UV command smoke tests (currently mostly “does not reject”).
src/test/managers/builtin/pipVersions.unit.test.ts Removes tests for the old pip-index-versions parsing helper.
src/test/managers/builtin/pipListUtils.unit.test.ts Removes tests for the old pip list / uv tree parsing helpers.
src/managers/poetry/poetryPackageManager.ts Switches Poetry package operations to command classes; refactors Poetry cwd selection into helper.
src/managers/conda/condaUtils.ts Removes superseded managePackages() helper.
src/managers/conda/condaPackageManager.ts Switches Conda package operations/list/version/available-versions to command classes.
src/managers/builtin/utils.ts Adds parsePackageSpecs() helper and removes older pip-related utility functions from this module.
src/managers/builtin/pipUtils.ts Switches installed-package enumeration to command classes; removes isPipInstallCommand().
src/managers/builtin/pipPackageManager.ts Switches pip/uv operations to command classes; refactors available versions and direct-name listing.
src/managers/builtin/pipListUtils.ts Deletes the old pip list / uv tree parsing module.
src/managers/builtin/helpers.ts Adjusts logging behavior for python stderr output.
package-lock.json Lockfile update (tslib metadata change).

Comment thread src/managers/builtin/pipPackageManager.ts Outdated
Comment thread src/managers/builtin/pipPackageManager.ts
Comment thread src/managers/builtin/utils.ts Outdated
Comment thread src/test/managers/builtin/commands.unit.test.ts Outdated
Comment thread src/test/managers/conda/commands.unit.test.ts Outdated
Comment thread src/test/managers/poetry/commands.unit.test.ts Outdated
Comment thread src/managers/builtin/helpers.ts
- pipPackageManager.manage(): rethrow CancellationError instead of swallowing
  it, so callers (e.g. venv creation's pkgInstallationCancelled) can distinguish
  cancel from failure; restores parity with main and the conda/poetry managers.
- getDirectPackageNames: fix docstring to reflect uv uses 'uv pip tree --depth=0'
  (not 'uv pip list --not-required').
- parsePackageSpecs: omit undefined version property and clarify wording.
- runPython: restore 'python:' prefix on stderr log output for consistency.
- Remove overlapping command smoke tests; the reworked, parsed-value versions
  are owned by the tests PR (#1677).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3f16397e-0917-4efb-8d75-566c71ebf9ba
Public-API-driven integration test exercising install/list/direct-deps/uninstall
for every discovered package manager, parametrized over environments grouped by
managerId so future managers are covered automatically. Consolidated into this PR
per review preference rather than a separate PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3f16397e-0917-4efb-8d75-566c71ebf9ba
Add a capability-guarded available-versions step to the package manager
roundtrip integration test. Uses an optional cast so it compiles and runs
regardless of whether the active API build surfaces the getter, and skips
the assertion for managers that resolve to undefined.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3f16397e-0917-4efb-8d75-566c71ebf9ba
The package-manager roundtrip hard-failed for conda on CI because cowsay is
not available on conda's default channels and conda surfaces install failures
as notifications rather than throwing, so the post-install assertion tripped.
Make the install step best-effort: verify presence after install and, when the
package did not install from the manager's configured sources, skip that manager
gracefully instead of failing. Managers that can install it still assert the
full lifecycle.

Also restore package-lock.json to match main (spurious tslib 'peer' metadata
churn from a local npm install; no package.json change) to satisfy the
changed-files check.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3f16397e-0917-4efb-8d75-566c71ebf9ba
…ndtrip

Switch the roundtrip integration test package from cowsay to flask.
cowsay is not on conda's default channels, so conda's managePackages
silently swallowed the failed install and the post-install assertion
tripped on CI. flask is available across all managers (incl. conda's
default main channel) and pulls in transitive deps (jinja2, werkzeug,
click, ...), letting the test verify direct-vs-transitive classification.

Install is a hard assertion again (no best-effort skip). The enriched
package list is read from refreshPackages' return value, since
getPackages({skipCache}) re-lists without isTransitive enrichment. The
transitive-dependency assertion is conditional on the manager classifying
transitivity at all (conda leaves isTransitive undefined). Bump per-test
timeout to 5m to accommodate conda solving flask + deps.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 3f16397e-0917-4efb-8d75-566c71ebf9ba

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/managers/builtin/pipPackageManager.ts:185

  • getPackages() now directly awaits listCmd.execute() and then caches the result. If runPython/runUV fails (e.g. pip missing/broken), execute() will reject and the public API call will throw rather than returning undefined as before, potentially breaking callers/UI. Consider catching execution errors here and returning undefined (and avoid caching an empty list on failure).
            const data = await listCmd.execute();
            const packages = (data ?? []).map((pkg) => this.api.createPackageItem(pkg, environment, this));
            this.packages.set(environment.envId.id, packages);
            return packages;

src/managers/builtin/pipUtils.ts:289

  • getWorkspacePackagesToInstall() now calls listCmd.execute() without any error handling. If pip/uv listing fails, this helper will throw and can abort the package selection flow. Previously the pip list path handled failures and returned undefined/empty results. Consider catching here and treating the installed list as unknown so the picker can still proceed.
                UvListCommand,
            );
            const data = await listCmd.execute();
            installed = data?.map((pkg) => pkg.name);
        }

src/managers/poetry/poetryPackageManager.ts:234

  • fetchPackagesFromTool() will currently throw (e.g. if Poetry is missing or poetry show fails), and PythonEnvironmentApi.getPackages() forwards manager errors without catching. To keep getPackages() resilient for callers/UI, consider making this helper return an empty list on tool failure (and log), rather than throwing.
        const cwd = await this.getPoetryCwd(environment);
        const showCmd = new PoetryShowCommand({
            pythonExecutable: poetry,
            cwd,
            log: this.log,

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@StellaHuang95

Stella Huang (StellaHuang95) commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

🔒 Automated review in progress — Stella Huang (@StellaHuang95) is auto-reviewing this PR.

Comment thread src/test/integration/packageManagerRoundtrip.integration.test.ts Outdated
Comment thread src/managers/poetry/poetryPackageManager.ts Outdated
Comment thread src/managers/builtin/pipPackageManager.ts Outdated
Comment thread src/managers/builtin/pipPackageManager.ts Outdated
@StellaHuang95

Copy link
Copy Markdown
Contributor

GitHub cannot anchor PR review comments to unchanged lines in the diff. Falling back to a general PR comment for src/test/managers/builtin/pipListUtils.unit.test.ts:L1.

Warning · Non-blocking recommendation

Deleting these parser tests removes deterministic malformed-output coverage for pip list, uv tree, and available-version parsing. The new live integration test does not exercise those branches; retain equivalent command-layer unit coverage in this change or ensure it is already present before removing these tests. [verified]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (5)

src/managers/builtin/pipPackageManager.ts:213

  • The newly added refresh error notification and its action label are user-facing but are not localized. Pass both strings through l10n.t() and compare against the localized action value.
                    const result = await showErrorMessage('Error refreshing packages', 'View Output');

src/managers/builtin/pipPackageManager.ts:271

  • PipAvailableVersionsCommand always adds --json, but this branch permits every pip version from 21.2 onward. The previous implementation only used JSON for pip >= 25.1 and parsed the text format for 21.2–25.0, so version lookup now fails and returns undefined for that supported range. Preserve the text fallback for pip < 25.1 (or extend the command abstraction to select the parser by pip version).
            // For pip < 21.2.0, check version first
            if (availableVersionsCmd instanceof PipAvailableVersionsCommand) {
                const pipVersion = await this.getVersion(environment);
                if (!pipVersion || compare(pipVersion.public, '21.2.0') < 0) {

src/managers/builtin/pipUtils.ts:289

  • A failure to execute the package-list command now rejects getWorkspacePackagesToInstall() and aborts the interactive package picker. Previously refreshPipPackages() caught this failure and continued with installed undefined, allowing users to select packages even when installed-package detection failed. Catch and log the command failure here while leaving installed undefined.
            const data = await listCmd.execute();
            installed = data?.map((pkg) => pkg.name);

src/managers/poetry/poetryPackageManager.ts:252

  • PoetryShowCommand.execute() rejects when Poetry exits unsuccessfully, and this call is no longer inside the old catch block. As a result, getPackages() now propagates transient Poetry failures instead of logging them and returning an empty package list as before, which can break API/UI callers. Restore the failure handling around command execution.
        const data = await showCmd.execute();
        return (data ?? []).map((pkg) => this.api.createPackageItem(pkg, environment, this));

src/managers/builtin/pipPackageManager.ts:153

  • These error-message and action-label strings are user-facing but bypass VS Code localization. Localize both values before passing them to showErrorMessage, and compare the result against the same localized action label.

This issue also appears on line 213 of the same file.

                            const result = await showErrorMessage('Error managing packages', 'View Output');

Comment thread src/managers/builtin/pipPackageManager.ts
Comment thread src/managers/builtin/pipUtils.ts Outdated
Comment thread src/test/managers/builtin/pipPackageManager.unit.test.ts
Comment thread src/managers/conda/condaPackageManager.ts Outdated
@StellaHuang95

Copy link
Copy Markdown
Contributor

Non-blocking: Poetry command helpers re-discover the executable instead of using the command object's configured executable, so configured executable selection is ignored.

Restore Pip version compatibility and picker fallback, add deterministic command tests, and move shared package helpers to a neutral module.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: edcaaa35-9a42-4351-98fa-55bcf8f1968e
Comment thread src/managers/poetry/poetryPackageManager.ts Outdated
Comment thread src/managers/poetry/poetryPackageManager.ts Outdated
@StellaHuang95

Copy link
Copy Markdown
Contributor

The new Poetry command path also has an executable-source mismatch: its runner rediscovers Poetry instead of spawning the command instance's injected executable. Thread the injected executable into the runner so selection remains consistent.

Keep package loading best-effort and retain process cwd for mutation and direct-package commands.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: edcaaa35-9a42-4351-98fa-55bcf8f1968e
@StellaHuang95

Copy link
Copy Markdown
Contributor

Non-blocking: Poetry command objects currently rediscover the executable instead of using their injected pythonExecutable, leaving two sources of truth. Consider threading the selected executable through runPoetry.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@StellaHuang95 Stella Huang (StellaHuang95) added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Aug 18, 2026

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

Comment thread src/managers/conda/condaPackageManager.ts
@StellaHuang95

Copy link
Copy Markdown
Contributor

The Poetry command runner also re-resolves the executable instead of using the injected one, leaving two executable sources of truth.

@StellaHuang95 Stella Huang (StellaHuang95) added review-auto:changes-requested Automated review: posted blocking findings to address. and removed review-auto:approved Automated review: no blocking findings (approval posted). labels Aug 18, 2026
Reject malformed and non-array conda list output so failed reads are not cached as valid empty environments. Add command parsing and manager retry coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot-Session: edcaaa35-9a42-4351-98fa-55bcf8f1968e
Comment thread src/test/integration/packageManagerRoundtrip.integration.test.ts Outdated
Comment thread src/managers/builtin/pipPackageManager.ts
Comment thread src/managers/builtin/pipUtils.ts Outdated
Comment thread src/test/managers/builtin/pipPackageManager.unit.test.ts
Comment thread src/managers/conda/condaPackageManager.ts Outdated
Comment thread src/managers/poetry/poetryPackageManager.ts Outdated
Comment thread src/managers/poetry/poetryPackageManager.ts Outdated
Comment thread src/managers/conda/condaPackageManager.ts
Comment thread src/managers/conda/condaPackageManager.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

debt Code quality issues review-auto:changes-requested Automated review: posted blocking findings to address.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants