Skip to content

Make variable resolvers based on environment including launch config env#299752

Merged
meganrogge merged 1 commit intomicrosoft:mainfrom
eliericha:richa/shell-env
Mar 7, 2026
Merged

Make variable resolvers based on environment including launch config env#299752
meganrogge merged 1 commit intomicrosoft:mainfrom
eliericha:richa/shell-env

Conversation

@eliericha
Copy link
Contributor

This PR fixes #299520.

The fix consists of making variable resolvers in local and remote terminal logic based on an environment that includes the environment coming from launch configurations.

As a result, ${env:...} expressions in terminal env settings resolve over an environment that is closer to the initial environment of terminals, and yield more meaningful values.

In the test source, a stub of getShellEnvironment is added to support testing.

Copilot AI review requested due to automatic review settings March 6, 2026 12:22
Copy link
Contributor

Copilot AI left a comment

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 adjusts terminal variable resolution so ${env:...} in terminal environment settings is resolved against an environment that better matches the terminal’s initial environment, including environment contributed by launch configurations (fixing #299520).

Changes:

  • Build the variable resolver environment from the base terminal environment, then merge in getShellEnvironment() to incorporate launch-config/shell-derived values.
  • In remote terminal creation on the server, use baseEnv (not process.env) as the resolver environment to preserve expected PATH/content (eg remote code CLI).
  • Update terminal tests to stub getShellEnvironment() on the test backend.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
src/vs/workbench/contrib/terminal/test/browser/terminalProcessManager.test.ts Extends the test backend stub with getShellEnvironment() to support the new call site.
src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts Constructs resolver env from base env + merged shell env before creating the variable resolver.
src/vs/server/node/remoteTerminalChannel.ts Uses baseEnv for variable resolution instead of process.env during remote terminal creation.

Comment on lines +267 to +268
const envForResolver = { ...await this._terminalProfileResolverService.getEnvironment(this.remoteAuthority) };
terminalEnvironment.mergeEnvironments(envForResolver, await backend.getShellEnvironment());
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

backend.getShellEnvironment() can contain variables from launch configuration / authority resolution that are explicitly set to null to unset them. mergeEnvironments supports null values to delete keys, but the remote backend implementation currently drops null values, so deletions won't be reflected in envForResolver and ${env:...} may resolve to a value that was intended to be removed. Consider preserving null entries in getShellEnvironment (or returning an ITerminalEnvironment) so deletions are applied correctly when merging.

Suggested change
const envForResolver = { ...await this._terminalProfileResolverService.getEnvironment(this.remoteAuthority) };
terminalEnvironment.mergeEnvironments(envForResolver, await backend.getShellEnvironment());
const baseEnv = await this._terminalProfileResolverService.getEnvironment(this.remoteAuthority);
const shellEnv = await backend.getShellEnvironment();
const envForResolver: ITerminalEnvironment = { ...baseEnv };
if (shellEnv) {
terminalEnvironment.mergeEnvironments(envForResolver, shellEnv);
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The suggested code is incorrectly typed. envForResolver is typed as an ITerminalEnvironment (supports null values) and passed as the first parameter of mergeEnvironments which expects an IProcessEnvironment (no null values).

Furthermore, the more general suggestion of preserving null entries in getShellEnvironment would require changing the interfaces which is a significant change that we probably don't want to make in the context of a bugfix.

Comment on lines +265 to +266
// available, then overlay the shell environment on top so that launch configuration
// variables and shell-profile modifications take precedence.
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The comment says the shell environment overlay includes "shell-profile modifications", but ITerminalBackend.getShellEnvironment is not consistently a full shell env across backends (eg remote backend returns only resolver-provided extension host env). Updating the comment to describe what’s actually being merged here (base env + resolver/launch-config-provided env) would avoid confusion for future maintenance.

Suggested change
// available, then overlay the shell environment on top so that launch configuration
// variables and shell-profile modifications take precedence.
// available, then overlay any environment provided by the backend (for example from
// the resolver or launch configuration) so that those values take precedence.

Copilot uses AI. Check for mistakes.
Comment on lines +264 to +269
// Start with the full base environment so that all standard variables (e.g. PATH) are
// available, then overlay the shell environment on top so that launch configuration
// variables and shell-profile modifications take precedence.
const envForResolver = { ...await this._terminalProfileResolverService.getEnvironment(this.remoteAuthority) };
terminalEnvironment.mergeEnvironments(envForResolver, await backend.getShellEnvironment());
const variableResolver = terminalEnvironment.createVariableResolver(this._cwdWorkspaceFolder, envForResolver, this._configurationResolverService);
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This changes how ${env:...} is resolved for terminal env settings by merging additional environment sources into the resolver input, but there’s no unit test asserting the new resolution behavior (eg launch-config env values taking precedence, and remote PATH/code CLI preservation). Adding a targeted test in the existing TerminalProcessManager test suite would help prevent regressions.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

@meganrogge meganrogge left a comment

Choose a reason for hiding this comment

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

Makes sense to me. Thanks! cc @Tyriar

@meganrogge meganrogge added this to the 1.112.0 milestone Mar 6, 2026
@meganrogge meganrogge enabled auto-merge (squash) March 6, 2026 17:56
@meganrogge meganrogge merged commit 2a7cdf8 into microsoft:main Mar 7, 2026
21 of 22 checks passed
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.

Unexpected ${env:...} environment variable resolution for terminals

4 participants