diff --git a/src/managers/conda/condaUtils.ts b/src/managers/conda/condaUtils.ts index 098aa9c7..24d18265 100644 --- a/src/managers/conda/condaUtils.ts +++ b/src/managers/conda/condaUtils.ts @@ -82,19 +82,21 @@ export function getCondaPathSetting(): string | undefined { } export async function getCondaForWorkspace(fsPath: string): Promise { + // Check persisted user selection first so explicit choices survive restarts + const state = await getWorkspacePersistentState(); + const data = await state.get(CONDA_WORKSPACE_KEY); + if (data && typeof data === 'object') { + const workspaceSelections = data as { [key: string]: string }; + if (Object.prototype.hasOwnProperty.call(workspaceSelections, fsPath)) { + return workspaceSelections[fsPath]; + } + } + + // Fall back to CONDA_PREFIX only when no explicit selection exists if (process.env.CONDA_PREFIX) { return process.env.CONDA_PREFIX; } - const state = await getWorkspacePersistentState(); - const data: { [key: string]: string } | undefined = await state.get(CONDA_WORKSPACE_KEY); - if (data) { - try { - return data[fsPath]; - } catch { - return undefined; - } - } return undefined; } diff --git a/src/test/managers/conda/condaUtils.getCondaForWorkspace.unit.test.ts b/src/test/managers/conda/condaUtils.getCondaForWorkspace.unit.test.ts new file mode 100644 index 00000000..22a10dc7 --- /dev/null +++ b/src/test/managers/conda/condaUtils.getCondaForWorkspace.unit.test.ts @@ -0,0 +1,107 @@ +import assert from 'assert'; +import * as sinon from 'sinon'; +import * as persistentState from '../../../common/persistentState'; +import { CONDA_WORKSPACE_KEY, getCondaForWorkspace } from '../../../managers/conda/condaUtils'; + +suite('Conda Utils - getCondaForWorkspace prioritization', () => { + let mockState: { get: sinon.SinonStub; set: sinon.SinonStub }; + let getWorkspacePersistentStateStub: sinon.SinonStub; + let originalCondaPrefix: string | undefined; + + setup(() => { + originalCondaPrefix = process.env.CONDA_PREFIX; + + mockState = { + get: sinon.stub(), + set: sinon.stub().resolves(), + }; + getWorkspacePersistentStateStub = sinon.stub(persistentState, 'getWorkspacePersistentState'); + getWorkspacePersistentStateStub.resolves(mockState); + }); + + teardown(() => { + if (originalCondaPrefix === undefined) { + delete process.env.CONDA_PREFIX; + } else { + process.env.CONDA_PREFIX = originalCondaPrefix; + } + sinon.restore(); + }); + + test('Persisted selection takes priority over CONDA_PREFIX', async () => { + const workspacePath = '/home/user/project'; + const userSelectedEnv = '/home/user/miniconda3/envs/myenv'; + process.env.CONDA_PREFIX = '/home/user/miniconda3'; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves({ + [workspacePath]: userSelectedEnv, + }); + + const result = await getCondaForWorkspace(workspacePath); + + assert.strictEqual(result, userSelectedEnv); + }); + + test('CONDA_PREFIX is used as fallback when no persisted selection exists', async () => { + const workspacePath = '/home/user/project'; + const condaBase = '/home/user/miniconda3'; + process.env.CONDA_PREFIX = condaBase; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves(undefined); + + const result = await getCondaForWorkspace(workspacePath); + + assert.strictEqual(result, condaBase); + }); + + test('CONDA_PREFIX is used when persisted data exists but not for this workspace', async () => { + const workspacePath = '/home/user/project'; + const condaBase = '/home/user/miniconda3'; + process.env.CONDA_PREFIX = condaBase; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves({ + '/home/user/other-project': '/home/user/miniconda3/envs/other', + }); + + const result = await getCondaForWorkspace(workspacePath); + + assert.strictEqual(result, condaBase); + }); + + test('Returns undefined when no persisted selection and no CONDA_PREFIX', async () => { + delete process.env.CONDA_PREFIX; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves(undefined); + + const result = await getCondaForWorkspace('/home/user/project'); + + assert.strictEqual(result, undefined); + }); + + test('Returns persisted selection when CONDA_PREFIX is not set', async () => { + const workspacePath = '/home/user/project'; + const userSelectedEnv = '/home/user/miniconda3/envs/myenv'; + delete process.env.CONDA_PREFIX; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves({ + [workspacePath]: userSelectedEnv, + }); + + const result = await getCondaForWorkspace(workspacePath); + + assert.strictEqual(result, userSelectedEnv); + }); + + test('Returns persisted empty string without falling back to CONDA_PREFIX', async () => { + const workspacePath = '/home/user/project'; + process.env.CONDA_PREFIX = '/home/user/miniconda3'; + + mockState.get.withArgs(CONDA_WORKSPACE_KEY).resolves({ + [workspacePath]: '', + }); + + const result = await getCondaForWorkspace(workspacePath); + + assert.strictEqual(result, ''); + }); +});