From 3fa8acce65a8776d0d126c0faa7b97d2082207ce Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 9 Oct 2026 15:26:04 -0700 Subject: [PATCH 1/4] API: Add getVersion method to EnvironmentManager --- src/managers/common/registeredManagers.ts | 4 +++ src/managers/conda/condaEnvManager.ts | 11 +++++++ src/managers/pipenv/pipenvManager.ts | 12 +++++++ src/managers/pipenv/pipenvUtils.ts | 19 +++++++++++ src/managers/poetry/poetryManager.ts | 10 ++++++ src/managers/pyenv/pyenvManager.ts | 12 +++++++ src/managers/pyenv/pyenvUtils.ts | 19 +++++++++++ src/test/features/envManagers.unit.test.ts | 27 +++++++++++++++- .../pipenv/pipenvUtils.getPipenv.unit.test.ts | 31 +++++++++++++++++- .../managers/pyenv/pyenvUtils.unit.test.ts | 32 ++++++++++++++++++- src/types.ts | 6 ++++ 11 files changed, 180 insertions(+), 3 deletions(-) diff --git a/src/managers/common/registeredManagers.ts b/src/managers/common/registeredManagers.ts index 834964cd3..37aa0c8d4 100644 --- a/src/managers/common/registeredManagers.ts +++ b/src/managers/common/registeredManagers.ts @@ -81,6 +81,10 @@ export class InternalEnvironmentManager implements EnvironmentManager { return this.manager.log; } + public getVersion(): Promise { + return this.manager.getVersion ? this.manager.getVersion() : Promise.resolve(undefined); + } + public get supportsCreate(): boolean { return this.manager.create !== undefined; } diff --git a/src/managers/conda/condaEnvManager.ts b/src/managers/conda/condaEnvManager.ts index adcf6264a..6d64ebcb4 100644 --- a/src/managers/conda/condaEnvManager.ts +++ b/src/managers/conda/condaEnvManager.ts @@ -20,6 +20,7 @@ import { GetEnvironmentScope, GetEnvironmentsScope, IconPath, + Pep440Version, PythonEnvironment, PythonEnvironmentApi, PythonProject, @@ -48,6 +49,7 @@ import { getProjectFsPathForScope, tryFastPathGet } from '../common/fastPath'; import { NativePythonFinder } from '../common/nativePythonFinder'; import { notifyMissingManagerIfDefault } from '../common/utils'; import { constructCondaSourcingStatus, CondaSourcingStatus } from './condaSourcingUtils'; +import { CondaVersionCommand } from './commands/version'; import { checkForNoPythonCondaEnvironment, clearCondaCache, @@ -105,6 +107,15 @@ export class CondaEnvManager implements EnvironmentManager, Disposable { this.fsPathToEnv.clear(); } + public async getVersion(): Promise { + try { + return await new CondaVersionCommand({ pythonExecutable: 'conda', log: this.log }).execute(); + } catch (error) { + traceInfo(`Unable to determine Conda version: ${error instanceof Error ? error.message : String(error)}`); + return undefined; + } + } + private _initialized: Deferred | undefined; private discovery: Deferred | undefined; private initializationError: unknown; diff --git a/src/managers/pipenv/pipenvManager.ts b/src/managers/pipenv/pipenvManager.ts index 6c21e16ab..250c4fffc 100644 --- a/src/managers/pipenv/pipenvManager.ts +++ b/src/managers/pipenv/pipenvManager.ts @@ -1,3 +1,4 @@ +import { explain as parsePep440Version } from '@renovatebot/pep440'; import { Disposable, EventEmitter, MarkdownString, ProgressLocation, Uri } from 'vscode'; import { DidChangeEnvironmentEventArgs, @@ -7,6 +8,7 @@ import { GetEnvironmentScope, GetEnvironmentsScope, IconPath, + Pep440Version, PythonEnvironment, PythonEnvironmentApi, PythonProject, @@ -38,6 +40,7 @@ import { getPipenv, getPipenvForGlobal, getPipenvForWorkspace, + getPipenvVersion, refreshPipenv, resolvePipenvPath, setPipenvForGlobal, @@ -83,6 +86,15 @@ export class PipenvManager implements EnvironmentManager, Disposable { this._onDidChangeEnvironments.dispose(); } + public async getVersion(): Promise { + const pipenv = await getPipenv(); + if (!pipenv) { + return undefined; + } + const version = await getPipenvVersion(pipenv); + return version ? (parsePep440Version(version) ?? undefined) : undefined; + } + private discovery: Deferred | undefined; private initializationError: unknown; readonly [pythonToolSupport]: EnvironmentToolSupport = { diff --git a/src/managers/pipenv/pipenvUtils.ts b/src/managers/pipenv/pipenvUtils.ts index 55e375e91..764f6ad2f 100644 --- a/src/managers/pipenv/pipenvUtils.ts +++ b/src/managers/pipenv/pipenvUtils.ts @@ -13,6 +13,7 @@ import { PythonEnvironmentApi, PythonEnvironmentInfo, } from '../../api'; +import { execProcess } from '../../common/childProcess.apis'; import { ENVS_EXTENSION_ID } from '../../common/constants'; import { traceError, traceInfo, traceVerbose } from '../../common/logging'; import { getWorkspacePersistentState } from '../../common/persistentState'; @@ -105,6 +106,24 @@ export async function getPipenv(): Promise { } } +/** + * Returns the version reported by the Pipenv executable. + * + * @param pipenv Path to the Pipenv executable. + * @returns The version string, or `undefined` when it cannot be determined. + */ +export async function getPipenvVersion(pipenv: string): Promise { + try { + const { stdout } = await execProcess(`"${pipenv}" --version`); + traceInfo(`Pipenv version output: ${stdout.trim()}`); + const match = stdout.match(/pipenv,?\s+(?:version\s+)?(\d+(?:\.\d+)+(?:[a-z0-9.-]*)?)/i); + return match?.[1]; + } catch (error) { + traceInfo(`Unable to determine Pipenv version: ${error instanceof Error ? error.message : String(error)}`); + return undefined; + } +} + async function nativeToPythonEnv( info: NativeEnvInfo, api: PythonEnvironmentApi, diff --git a/src/managers/poetry/poetryManager.ts b/src/managers/poetry/poetryManager.ts index b969ca47e..00041932b 100644 --- a/src/managers/poetry/poetryManager.ts +++ b/src/managers/poetry/poetryManager.ts @@ -8,6 +8,7 @@ import { GetEnvironmentScope, GetEnvironmentsScope, IconPath, + Pep440Version, PythonEnvironment, PythonEnvironmentApi, PythonProject, @@ -45,6 +46,7 @@ import { setPoetryForWorkspace, setPoetryForWorkspaces, } from './poetryUtils'; +import { PoetryVersionCommand } from './commands/version'; export class PoetryManager implements EnvironmentManager, Disposable { private collection: PythonEnvironment[] = []; @@ -80,6 +82,14 @@ export class PoetryManager implements EnvironmentManager, Disposable { this.fsPathToEnv.clear(); } + public async getVersion(): Promise { + const poetry = await getPoetry(); + if (!poetry) { + return undefined; + } + return await new PoetryVersionCommand({ pythonExecutable: poetry }).execute(); + } + private _initialized: Deferred | undefined; private discovery: Deferred | undefined; private initializationError: unknown; diff --git a/src/managers/pyenv/pyenvManager.ts b/src/managers/pyenv/pyenvManager.ts index 05b4447b5..b1c2e914d 100644 --- a/src/managers/pyenv/pyenvManager.ts +++ b/src/managers/pyenv/pyenvManager.ts @@ -1,3 +1,4 @@ +import { explain as parsePep440Version } from '@renovatebot/pep440'; import * as path from 'path'; import { Disposable, EventEmitter, MarkdownString, ProgressLocation, Uri } from 'vscode'; import { @@ -8,6 +9,7 @@ import { GetEnvironmentScope, GetEnvironmentsScope, IconPath, + Pep440Version, PythonEnvironment, PythonEnvironmentApi, PythonProject, @@ -35,6 +37,7 @@ import { getPyenv, getPyenvForGlobal, getPyenvForWorkspace, + getPyenvVersion, PYENV_VERSIONS, refreshPyenv, resolvePyenvPath, @@ -77,6 +80,15 @@ export class PyEnvManager implements EnvironmentManager, Disposable { this.fsPathToEnv.clear(); } + public async getVersion(): Promise { + const pyenv = await getPyenv(); + if (!pyenv) { + return undefined; + } + const version = await getPyenvVersion(pyenv); + return version ? (parsePep440Version(version) ?? undefined) : undefined; + } + private _initialized: Deferred | undefined; private discovery: Deferred | undefined; private initializationError: unknown; diff --git a/src/managers/pyenv/pyenvUtils.ts b/src/managers/pyenv/pyenvUtils.ts index 2e49ad0e2..16dcfa3e6 100644 --- a/src/managers/pyenv/pyenvUtils.ts +++ b/src/managers/pyenv/pyenvUtils.ts @@ -9,6 +9,7 @@ import { PythonEnvironmentApi, PythonEnvironmentInfo, } from '../../api'; +import { execProcess } from '../../common/childProcess.apis'; import { ENVS_EXTENSION_ID } from '../../common/constants'; import { traceError, traceInfo } from '../../common/logging'; import { getWorkspacePersistentState } from '../../common/persistentState'; @@ -170,6 +171,24 @@ export async function getPyenv(): Promise { } } +/** + * Returns the version reported by the Pyenv executable. + * + * @param pyenv Path to the Pyenv executable. + * @returns The version string, or `undefined` when it cannot be determined. + */ +export async function getPyenvVersion(pyenv: string): Promise { + try { + const { stdout } = await execProcess(`"${pyenv}" --version`); + traceInfo(`Pyenv version output: ${stdout.trim()}`); + const match = stdout.match(/pyenv(?:-win)?\s+(\d+(?:\.\d+)+(?:[a-z0-9.-]*)?)/i); + return match?.[1]; + } catch (error) { + traceInfo(`Unable to determine Pyenv version: ${error instanceof Error ? error.message : String(error)}`); + return undefined; + } +} + function nativeToPythonEnv( info: NativeEnvInfo, api: PythonEnvironmentApi, diff --git a/src/test/features/envManagers.unit.test.ts b/src/test/features/envManagers.unit.test.ts index 63db6773f..3879a2fce 100644 --- a/src/test/features/envManagers.unit.test.ts +++ b/src/test/features/envManagers.unit.test.ts @@ -4,6 +4,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as assert from 'assert'; +import { explain as parsePep440Version } from '@renovatebot/pep440'; import * as sinon from 'sinon'; import { Uri } from 'vscode'; import { PythonEnvironment } from '../../api'; @@ -76,11 +77,16 @@ suite('PythonEnvironmentManagers - getEnvironment', () => { /** * Registers a fake environment manager that returns predefined environments. */ - function registerFakeManager(managerId: string, getStub: sinon.SinonStub): void { + function registerFakeManager( + managerId: string, + getStub: sinon.SinonStub, + getVersion?: sinon.SinonStub, + ): void { const fakeManager = { name: managerId.split(':')[1], displayName: managerId, preferredPackageManagerId: 'ms-python.python:pip', + getVersion, get: getStub, set: sandbox.stub().resolves(), resolve: sandbox.stub().resolves(undefined), @@ -145,6 +151,25 @@ suite('PythonEnvironmentManagers - getEnvironment', () => { assert.ok(getStub.calledOnce, 'Should delegate to manager.get()'); }); + test('should delegate getVersion to the registered manager', async () => { + const version = parsePep440Version('1.2.3'); + const getVersion = sandbox.stub().resolves(version); + registerFakeManager('ms-python.python:system', sandbox.stub().resolves(env311), getVersion); + + const result = await envManagers.getEnvironmentManager('ms-python.python:system')?.getVersion(); + + assert.deepStrictEqual(result, version); + assert.ok(getVersion.calledOnce, 'Should delegate to manager.getVersion()'); + }); + + test('should return undefined when the registered manager does not provide getVersion', async () => { + registerFakeManager('ms-python.python:system', sandbox.stub().resolves(env311)); + + const result = await envManagers.getEnvironmentManager('ms-python.python:system')?.getVersion(); + + assert.strictEqual(result, undefined); + }); + test('should return undefined when no managers are registered', async () => { // No managers registered at all — size === 0 guard fires const result = await envManagers.getEnvironment(Uri.file('/some/unknown/path')); diff --git a/src/test/managers/pipenv/pipenvUtils.getPipenv.unit.test.ts b/src/test/managers/pipenv/pipenvUtils.getPipenv.unit.test.ts index 1ffa934e4..9346e1cb3 100644 --- a/src/test/managers/pipenv/pipenvUtils.getPipenv.unit.test.ts +++ b/src/test/managers/pipenv/pipenvUtils.getPipenv.unit.test.ts @@ -1,9 +1,15 @@ import assert from 'assert'; import * as sinon from 'sinon'; +import * as childProcessApis from '../../../common/childProcess.apis'; import * as logging from '../../../common/logging'; import * as persistentState from '../../../common/persistentState'; import * as settingHelpers from '../../../features/settings/settingHelpers'; -import { clearPipenvCache, getPipenv, PIPENV_PATH_KEY } from '../../../managers/pipenv/pipenvUtils'; +import { + clearPipenvCache, + getPipenv, + getPipenvVersion, + PIPENV_PATH_KEY, +} from '../../../managers/pipenv/pipenvUtils'; /** * Tests for getPipenv prioritization. @@ -110,3 +116,26 @@ suite('Pipenv Utils - getPipenv prioritization', () => { return promise; }); }); + +suite('Pipenv Utils - getPipenvVersion', () => { + teardown(() => { + sinon.restore(); + }); + + test('parses the Pipenv version', async () => { + const execProcess = sinon + .stub(childProcessApis, 'execProcess') + .resolves({ stdout: 'pipenv, version 2024.4.1\n', stderr: '' }); + + const version = await getPipenvVersion('pipenv'); + + assert.strictEqual(version, '2024.4.1'); + assert.ok(execProcess.calledWith('"pipenv" --version')); + }); + + test('returns undefined when the command fails', async () => { + sinon.stub(childProcessApis, 'execProcess').rejects(new Error('Command not found')); + + assert.strictEqual(await getPipenvVersion('pipenv'), undefined); + }); +}); diff --git a/src/test/managers/pyenv/pyenvUtils.unit.test.ts b/src/test/managers/pyenv/pyenvUtils.unit.test.ts index 0f7024d7c..570ede927 100644 --- a/src/test/managers/pyenv/pyenvUtils.unit.test.ts +++ b/src/test/managers/pyenv/pyenvUtils.unit.test.ts @@ -1,7 +1,8 @@ import assert from 'node:assert'; import * as path from 'path'; import * as sinon from 'sinon'; -import { getPyenvDir } from '../../../managers/pyenv/pyenvUtils'; +import * as childProcessApis from '../../../common/childProcess.apis'; +import { getPyenvDir, getPyenvVersion } from '../../../managers/pyenv/pyenvUtils'; suite('pyenvUtils - getPyenvDir', () => { let originalPyenvRoot: string | undefined; @@ -42,3 +43,32 @@ suite('pyenvUtils - getPyenvDir', () => { assert.strictEqual(result, path.join('C:', 'Users', 'user', '.pyenv', 'pyenv-win')); }); }); + +suite('pyenvUtils - getPyenvVersion', () => { + teardown(() => { + sinon.restore(); + }); + + test('parses the Pyenv version', async () => { + const execProcess = sinon + .stub(childProcessApis, 'execProcess') + .resolves({ stdout: 'pyenv 2.5.3\n', stderr: '' }); + + const version = await getPyenvVersion('pyenv'); + + assert.strictEqual(version, '2.5.3'); + assert.ok(execProcess.calledWith('"pyenv" --version')); + }); + + test('parses the Pyenv for Windows version', async () => { + sinon.stub(childProcessApis, 'execProcess').resolves({ stdout: 'pyenv-win 3.1.1\n', stderr: '' }); + + assert.strictEqual(await getPyenvVersion('pyenv.bat'), '3.1.1'); + }); + + test('returns undefined when the command fails', async () => { + sinon.stub(childProcessApis, 'execProcess').rejects(new Error('Command not found')); + + assert.strictEqual(await getPyenvVersion('pyenv'), undefined); + }); +}); diff --git a/src/types.ts b/src/types.ts index 8699ce618..f3cfd72ae 100644 --- a/src/types.ts +++ b/src/types.ts @@ -411,6 +411,12 @@ export interface EnvironmentManager { */ readonly log?: LogOutputChannel; + /** + * Returns the version of the underlying environment management tool. + * @returns A promise that resolves to a {@link Pep440Version} object, or `undefined` if not available. + */ + getVersion?(): Promise; + /** * The quick create details for the environment manager. Having this method also enables the quick create feature * for the environment manager. Should Implement {@link EnvironmentManager.create} to support quick create. From 21f08fbf246023df18dd3687306ce18996d86ff6 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 9 Oct 2026 15:37:34 -0700 Subject: [PATCH 2/4] Bump version and changelog --- api/CHANGELOG.md | 6 ++++++ api/package-lock.json | 4 ++-- api/package.json | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index eb86291b4..00c157869 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to the `@vscode/python-environments` API package are documen The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.6.0] + +### Added + +- Added optional `EnvironmentManager.getVersion?(): Promise` support for retrieving the version of the underlying environment management tool. Built-in implementations are provided for Conda, Poetry, Pipenv, and Pyenv. + ## [1.5.0] ### Added diff --git a/api/package-lock.json b/api/package-lock.json index 3bd3d3a32..3be873d42 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1,12 +1,12 @@ { "name": "@vscode/python-environments", - "version": "1.5.0", + "version": "1.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@vscode/python-environments", - "version": "1.5.0", + "version": "1.6.0", "license": "MIT", "dependencies": { "@renovatebot/pep440": "^3.1.0" diff --git a/api/package.json b/api/package.json index ada2db299..b2be12d99 100644 --- a/api/package.json +++ b/api/package.json @@ -1,7 +1,7 @@ { "name": "@vscode/python-environments", "description": "An API facade for the Python Environments extension in VS Code", - "version": "1.5.0", + "version": "1.6.0", "author": { "name": "Microsoft Corporation" }, From c224979c43be6109f279a6df481c0b34287cf134 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 9 Oct 2026 15:45:04 -0700 Subject: [PATCH 3/4] Update README --- docs/README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index bbeb1b09a..7fd0ce7d6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -734,9 +734,9 @@ const c: PackageManagementOptions = { #### `Pep440Version` Re-exported from `@renovatebot/pep440`. Represents a parsed PEP 440 version, -returned by `getPackageAvailableVersions` and by a package manager's -`getVersion`. Import it from `@vscode/python-environments` so your types match -the API exactly. +returned by `getPackageAvailableVersions` and by environment and package +managers' `getVersion` methods. Import it from +`@vscode/python-environments` so your types match the API exactly. | Field | Type | Required | Description | | --- | --- | --- | --- | @@ -1556,6 +1556,7 @@ trigger, as the specification. | `tooltip` | `string \| MarkdownString` | No | Hover text for the manager. | | `iconPath` | [`IconPath`](#iconpath) | No | Icon shown for the manager. | | `log` | `LogOutputChannel` | No | Output channel used for the manager's logs. | +| `getVersion()` | `() => Promise` | No | Returns the parsed PEP 440 version of the underlying environment management tool. Return `undefined` when the manager has no versioned tool or its version is unavailable. | | `getEnvironments(scope)` | `(scope: GetEnvironmentsScope) => Promise` | Yes | Returns the environments known for the scope. Called frequently by UI surfaces. | | `refresh(scope)` | `(scope: RefreshEnvironmentsScope) => Promise` | Yes | Re-discovers environments for the scope. | | `set(scope, environment?)` | `(scope: SetEnvironmentScope, environment?: PythonEnvironment) => Promise` | Yes | Sets or clears the active environment for the scope. Also called at startup to rehydrate persisted state. | @@ -1576,6 +1577,10 @@ class MyEnvManager implements EnvironmentManager { constructor(private readonly api: PythonEnvironmentApi) {} + async getVersion(): Promise { + return getMyManagerVersion(); + } + async getEnvironments( scope: GetEnvironmentsScope, ): Promise { From f43d66dcad96f61b528ad3760b14e270992d0698 Mon Sep 17 00:00:00 2001 From: Eduardo Villalpando Mello Date: Fri, 9 Oct 2026 15:56:34 -0700 Subject: [PATCH 4/4] Addressed pr comments --- src/managers/conda/commands/version.ts | 4 ++-- src/managers/conda/condaUtils.ts | 6 +++++- src/managers/pyenv/pyenvUtils.ts | 2 +- src/test/managers/conda/commands.unit.test.ts | 6 ++++-- src/test/managers/pyenv/pyenvUtils.unit.test.ts | 8 ++++++++ 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/managers/conda/commands/version.ts b/src/managers/conda/commands/version.ts index e9921b2cc..28cbed545 100644 --- a/src/managers/conda/commands/version.ts +++ b/src/managers/conda/commands/version.ts @@ -1,7 +1,7 @@ import type { Pep440Version } from '@renovatebot/pep440'; import { explain as parsePep440Version } from '@renovatebot/pep440'; import { VersionCommand, type BaseExecuteArgs } from '../../base/commands/index'; -import { runCondaExecutable } from '../condaUtils'; +import { runConda } from '../condaUtils'; /** * Conda version command. @@ -14,7 +14,7 @@ export class CondaVersionCommand extends VersionCommand { } async execute(executeArgs?: BaseExecuteArgs): Promise { - const output = await runCondaExecutable(this.buildCommand(), this.log, executeArgs?.cancellationToken); + const output = await runConda(this.buildCommand(), this.log, executeArgs?.cancellationToken); // "conda X.Y.Z" const match = output.match(/conda\s+(\d+\.\d+(?:\.\d+)*)/i); diff --git a/src/managers/conda/condaUtils.ts b/src/managers/conda/condaUtils.ts index dd0df78fe..426137adb 100644 --- a/src/managers/conda/condaUtils.ts +++ b/src/managers/conda/condaUtils.ts @@ -283,7 +283,11 @@ async function _runConda( } } -async function runConda(args: string[], log?: LogOutputChannel, token?: CancellationToken): Promise { +export async function runConda( + args: string[], + log?: LogOutputChannel, + token?: CancellationToken, +): Promise { const conda = await getConda(); return await _runConda(conda, args, log, token); } diff --git a/src/managers/pyenv/pyenvUtils.ts b/src/managers/pyenv/pyenvUtils.ts index 16dcfa3e6..e3cf1e36e 100644 --- a/src/managers/pyenv/pyenvUtils.ts +++ b/src/managers/pyenv/pyenvUtils.ts @@ -181,7 +181,7 @@ export async function getPyenvVersion(pyenv: string): Promise { let environmentPath: string; let mockLog: LogOutputChannel; let runCondaStub: sinon.SinonStub; + let runConfiguredCondaStub: sinon.SinonStub; setup(() => { environmentPath = Uri.file('environment').fsPath; @@ -22,6 +23,7 @@ suite('Conda commands', () => { get: () => undefined, } as unknown as ReturnType); runCondaStub = sinon.stub(condaUtils, 'runCondaExecutable').resolves(''); + runConfiguredCondaStub = sinon.stub(condaUtils, 'runConda').resolves(''); }); teardown(() => { @@ -142,12 +144,12 @@ suite('Conda commands', () => { }); test('CondaVersionCommand parses the version', async () => { - runCondaStub.resolves('conda 24.1.2'); + runConfiguredCondaStub.resolves('conda 24.1.2'); const command = new CondaVersionCommand({ pythonExecutable: 'conda', log: mockLog }); const result = await command.execute(); - assert.deepStrictEqual(runCondaStub.firstCall.args[0], ['--version']); + assert.deepStrictEqual(runConfiguredCondaStub.firstCall.args[0], ['--version']); assert.strictEqual(result?.public, '24.1.2'); }); }); diff --git a/src/test/managers/pyenv/pyenvUtils.unit.test.ts b/src/test/managers/pyenv/pyenvUtils.unit.test.ts index 570ede927..0b856997c 100644 --- a/src/test/managers/pyenv/pyenvUtils.unit.test.ts +++ b/src/test/managers/pyenv/pyenvUtils.unit.test.ts @@ -66,6 +66,14 @@ suite('pyenvUtils - getPyenvVersion', () => { assert.strictEqual(await getPyenvVersion('pyenv.bat'), '3.1.1'); }); + test('returns the PEP 440 release from a git-describe version', async () => { + sinon + .stub(childProcessApis, 'execProcess') + .resolves({ stdout: 'pyenv 2.3.24-19-gabcdef1\n', stderr: '' }); + + assert.strictEqual(await getPyenvVersion('pyenv'), '2.3.24'); + }); + test('returns undefined when the command fails', async () => { sinon.stub(childProcessApis, 'execProcess').rejects(new Error('Command not found'));