Skip to content

Commit 9af2960

Browse files
committed
Merge origin/main into package-manager-command-adoption
Prefer main for overlapping package manager changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: edcaaa35-9a42-4351-98fa-55bcf8f1968e
2 parents 9edd9ef + c3cb023 commit 9af2960

29 files changed

Lines changed: 1407 additions & 478 deletions

.github/instructions/testing-workflow.instructions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,4 @@ envConfig.inspect
606606
- **Never skip tests to hide infrastructure problems**: If tests require native binaries (like `pet`), the CI workflow must build/download them. Skipping tests when infrastructure is missing gives false confidence. Build from source (like vscode-python does) rather than skipping. Tests should fail clearly when something is wrong (2)
607607
- **No retries for masking flakiness**: Mocha `retries` should not be used to mask test flakiness. If a test is flaky, fix the root cause. Retries hide real issues and slow down CI (1)
608608
- **pet binary is required for environment manager registration**: The smoke/E2E/integration tests require the `pet` binary from `microsoft/python-environment-tools` to be built and placed in `python-env-tools/bin/`. Without it, `waitForApiReady()` will timeout because managers never register. CI must build pet from source using `cargo build --release --package pet` (2)
609+
- **Check exact project registration with `getPythonProjects()`**: `getPythonProject(uri)` can return a containing parent project, so it cannot prove that a nested project was registered or unregistered (1)

.github/workflows/pr-check.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,14 @@ jobs:
335335
if: runner.os != 'Linux'
336336
run: npm run integration-test
337337

338+
- name: Run Package Manager Network Integration Tests
339+
if: runner.os == 'Linux' && matrix.python-version == '3.12'
340+
uses: GabrielBB/xvfb-action@86d97bde4a65fe9b290c0b3fb92c2c4ed0e5302d # v1.6
341+
env:
342+
VSC_PYTHON_PACKAGE_NETWORK_TEST: '1'
343+
with:
344+
run: npm run integration-test -- --grep "Package Manager"
345+
338346
integration-tests-multiroot:
339347
name: Integration Tests (Multi-Root)
340348
runs-on: ${{ matrix.os }}

.github/workflows/push-check.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,11 @@ jobs:
335335
- name: Run Integration Tests (non-Linux)
336336
if: runner.os != 'Linux'
337337
run: npm run integration-test
338+
339+
- name: Run Package Manager Network Integration Tests
340+
if: runner.os == 'Linux' && matrix.python-version == '3.12'
341+
uses: GabrielBB/xvfb-action@86d97bde4a65fe9b290c0b3fb92c2c4ed0e5302d # v1.6
342+
env:
343+
VSC_PYTHON_PACKAGE_NETWORK_TEST: '1'
344+
with:
345+
run: npm run integration-test -- --grep "Package Manager"

api/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to the `@vscode/python-environments` API package are documen
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.2.0]
9+
10+
### Added
11+
12+
- Added `PackageManagementInteractionOptions` with an optional `runHeadless?: boolean` property, mixed into `PackageManagementOptions`. When `true`, package management operations run without any user prompts or interaction — steps that would normally require input, such as selecting packages to install when none are specified, are skipped instead of prompting — for automated or headless scenarios such as integration tests.
13+
- Added `RemoveEnvironmentOptions` with an optional `runHeadless?: boolean` property to remove environments without a confirmation prompt in automated or headless scenarios.
14+
815
## [1.1.0]
916

1017
### Added

api/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@vscode/python-environments",
33
"description": "An API facade for the Python Environments extension in VS Code",
4-
"version": "1.1.0",
4+
"version": "1.2.0",
55
"author": {
66
"name": "Microsoft Corporation"
77
},

examples/sample1/src/api.ts

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,17 @@ export interface QuickCreateConfig {
329329
readonly detail?: string;
330330
}
331331

332+
/**
333+
* Options controlling environment removal.
334+
*/
335+
export interface RemoveEnvironmentOptions {
336+
/**
337+
* When `true`, removes the environment without prompting for confirmation.
338+
* Intended for automated or headless scenarios. Defaults to `false`.
339+
*/
340+
runHeadless?: boolean;
341+
}
342+
332343
/**
333344
* Interface representing an environment manager.
334345
*/
@@ -392,7 +403,7 @@ export interface EnvironmentManager {
392403
* @param environment - The Python environment to remove.
393404
* @returns A promise that resolves when the environment is removed.
394405
*/
395-
remove?(environment: PythonEnvironment): Promise<void>;
406+
remove?(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
396407

397408
/**
398409
* Refreshes the list of Python environments within the specified scope.
@@ -739,49 +750,62 @@ export interface GetPackagesOptions {
739750
}
740751

741752
/**
742-
* Options for package management.
753+
* Options controlling user interaction during package management operations.
743754
*/
744-
export type PackageManagementOptions =
745-
| {
746-
/**
747-
* Upgrade the packages if it is already installed.
748-
*/
749-
upgrade?: boolean;
750-
751-
/**
752-
* Show option to skip package installation
753-
*/
754-
showSkipOption?: boolean;
755-
/**
756-
* The list of packages to install.
757-
*/
758-
install: string[];
759-
760-
/**
761-
* The list of packages to uninstall.
762-
*/
763-
uninstall?: string[];
764-
}
765-
| {
766-
/**
767-
* Upgrade the packages if it is already installed.
768-
*/
769-
upgrade?: boolean;
770-
771-
/**
772-
* Show option to skip package installation
773-
*/
774-
showSkipOption?: boolean;
775-
/**
776-
* The list of packages to install.
777-
*/
778-
install?: string[];
755+
export interface PackageManagementInteractionOptions {
756+
/**
757+
* When `true`, the package management operation runs without any user prompts or
758+
* interaction and relies solely on the packages provided in the options. Any step
759+
* that would normally require user input — such as selecting packages to install
760+
* when none are specified — is skipped instead of prompting the user. Intended for
761+
* automated or headless scenarios such as integration tests. Defaults to `false`.
762+
*/
763+
runHeadless?: boolean;
764+
}
779765

780-
/**
781-
* The list of packages to uninstall.
782-
*/
783-
uninstall: string[];
784-
};
766+
export type PackageManagementOptions = PackageManagementInteractionOptions &
767+
(
768+
| {
769+
/**
770+
* Upgrade the packages if it is already installed.
771+
*/
772+
upgrade?: boolean;
773+
774+
/**
775+
* Show option to skip package installation or uninstallation.
776+
*/
777+
showSkipOption?: boolean;
778+
/**
779+
* The list of packages to install.
780+
*/
781+
install: string[];
782+
783+
/**
784+
* The list of packages to uninstall.
785+
*/
786+
uninstall?: string[];
787+
}
788+
| {
789+
/**
790+
* Upgrade the packages if it is already installed.
791+
*/
792+
upgrade?: boolean;
793+
794+
/**
795+
* Show option to skip package installation or uninstallation.
796+
*/
797+
showSkipOption?: boolean;
798+
/**
799+
* The list of packages to install.
800+
*/
801+
install?: string[];
802+
803+
/**
804+
* The list of packages to uninstall.
805+
*/
806+
uninstall: string[];
807+
}
808+
);
785809

786810
/**
787811
* Options for creating a Python environment.
@@ -881,9 +905,10 @@ export interface PythonEnvironmentManagementApi {
881905
* Remove a Python environment.
882906
*
883907
* @param environment The Python environment to remove.
908+
* @param options Optional parameters controlling environment removal.
884909
* @returns A promise that resolves when the environment has been removed.
885910
*/
886-
removeEnvironment(environment: PythonEnvironment): Promise<void>;
911+
removeEnvironment(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
887912
}
888913

889914
export interface PythonEnvironmentsApi {

src/api.ts

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,17 @@ export interface QuickCreateConfig {
345345
readonly detail?: string;
346346
}
347347

348+
/**
349+
* Options controlling environment removal.
350+
*/
351+
export interface RemoveEnvironmentOptions {
352+
/**
353+
* When `true`, removes the environment without prompting for confirmation.
354+
* Intended for automated or headless scenarios. Defaults to `false`.
355+
*/
356+
runHeadless?: boolean;
357+
}
358+
348359
/**
349360
* Interface representing an environment manager.
350361
*
@@ -425,7 +436,7 @@ export interface EnvironmentManager {
425436
* Invoked to delete the given environment. Typical triggers include an explicit user
426437
* action (such as a "Delete Environment" command) and programmatic removal via the API.
427438
*/
428-
remove?(environment: PythonEnvironment): Promise<void>;
439+
remove?(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
429440

430441
/**
431442
* Refreshes the list of Python environments within the specified scope.
@@ -872,47 +883,63 @@ export interface GetPackagesOptions {
872883
skipCache?: boolean;
873884
}
874885

875-
export type PackageManagementOptions =
876-
| {
877-
/**
878-
* Upgrade the packages if they are already installed.
879-
*/
880-
upgrade?: boolean;
881-
882-
/**
883-
* Show option to skip package installation or uninstallation.
884-
*/
885-
showSkipOption?: boolean;
886-
/**
887-
* The list of packages to install.
888-
*/
889-
install: string[];
890-
891-
/**
892-
* The list of packages to uninstall.
893-
*/
894-
uninstall?: string[];
895-
}
896-
| {
897-
/**
898-
* Upgrade the packages if they are already installed.
899-
*/
900-
upgrade?: boolean;
901-
902-
/**
903-
* Show option to skip package installation or uninstallation.
904-
*/
905-
showSkipOption?: boolean;
906-
/**
907-
* The list of packages to install.
908-
*/
909-
install?: string[];
886+
/**
887+
* Options controlling user interaction during package management operations.
888+
*/
889+
export interface PackageManagementInteractionOptions {
890+
/**
891+
* When `true`, the package management operation runs without any user prompts or
892+
* interaction and relies solely on the packages provided in the options. Any step
893+
* that would normally require user input — such as selecting packages to install
894+
* when none are specified — is skipped instead of prompting the user. Intended for
895+
* automated or headless scenarios such as integration tests. Defaults to `false`.
896+
*/
897+
runHeadless?: boolean;
898+
}
910899

911-
/**
912-
* The list of packages to uninstall.
913-
*/
914-
uninstall: string[];
915-
};
900+
export type PackageManagementOptions = PackageManagementInteractionOptions &
901+
(
902+
| {
903+
/**
904+
* Upgrade the packages if they are already installed.
905+
*/
906+
upgrade?: boolean;
907+
908+
/**
909+
* Show option to skip package installation or uninstallation.
910+
*/
911+
showSkipOption?: boolean;
912+
/**
913+
* The list of packages to install.
914+
*/
915+
install: string[];
916+
917+
/**
918+
* The list of packages to uninstall.
919+
*/
920+
uninstall?: string[];
921+
}
922+
| {
923+
/**
924+
* Upgrade the packages if they are already installed.
925+
*/
926+
upgrade?: boolean;
927+
928+
/**
929+
* Show option to skip package installation or uninstallation.
930+
*/
931+
showSkipOption?: boolean;
932+
/**
933+
* The list of packages to install.
934+
*/
935+
install?: string[];
936+
937+
/**
938+
* The list of packages to uninstall.
939+
*/
940+
uninstall: string[];
941+
}
942+
);
916943

917944
/**
918945
* Options for creating a Python environment.
@@ -1011,9 +1038,10 @@ export interface PythonEnvironmentManagementApi {
10111038
* Remove a Python environment.
10121039
*
10131040
* @param environment The Python environment to remove.
1041+
* @param options Optional parameters controlling environment removal.
10141042
* @returns A promise that resolves when the environment has been removed.
10151043
*/
1016-
removeEnvironment(environment: PythonEnvironment): Promise<void>;
1044+
removeEnvironment(environment: PythonEnvironment, options?: RemoveEnvironmentOptions): Promise<void>;
10171045
}
10181046

10191047
export interface PythonEnvironmentsApi {

src/extension.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,21 @@ export async function activate(context: ExtensionContext): Promise<PythonEnviron
258258
},
259259
);
260260
}),
261+
...(process.env.VSC_PYTHON_INTEGRATION_TEST === '1'
262+
? [
263+
commands.registerCommand('python-envs.test.getPackageManagerIds', () =>
264+
envManagers.packageManagers.map((manager) => manager.id),
265+
),
266+
commands.registerCommand(
267+
'python-envs.test.getDirectPackageNames',
268+
async (environment: PythonEnvironment) => {
269+
const manager = envManagers.getPackageManager(environment);
270+
const names = await manager?.getDirectPackageNames?.(environment);
271+
return names ? Array.from(names) : undefined;
272+
},
273+
),
274+
]
275+
: []),
261276
commands.registerCommand('python-envs.searchSettings', async () => {
262277
await openSearchSettings();
263278
}),

0 commit comments

Comments
 (0)