Add environment variables to CommandOptions - #44
Merged
Conversation
ProcessStartInfo.Environment was never touched, so a child always inherited the host's environment verbatim with no way to add, override or remove a variable for a single call. That blocks a class of CLI behaviour with no flag equivalent: GIT_TERMINAL_PROMPT=0, without which a fetch needing credentials blocks forever on a prompt no terminal will answer; GIT_ASKPASS and SSH_ASKPASS, the supported way to supply credentials without exposing them in a process listing; and LC_ALL=C, without which output parsing silently depends on the host locale. The entries are an overlay rather than a replacement, so a name that is not listed keeps whatever the caller had, and a null value removes a variable, matching ProcessStartInfo.Environment semantics. Leaving the property null preserves today's behaviour exactly. Elevation requires UseShellExecute, which has nowhere to put an environment, so combining the two throws rather than silently dropping variables a caller may be relying on for credentials. Fixes #40
matt-edmondson
force-pushed
the
feat/39-working-directory
branch
from
August 19, 2026 10:43
b7b8478 to
c99e717
Compare
matt-edmondson
force-pushed
the
feat/40-environment-variables
branch
from
August 19, 2026 10:43
f59f8a1 to
ed58449
Compare
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Fixes #40.
Problem
ProcessStartInfo.Environmentwas never touched, so the child always inherited the host's environment verbatim with no way to add, override or remove a variable for a single call. Environment variables are the only control surface some tools expose, so this blocked behaviour with no flag equivalent:GIT_TERMINAL_PROMPT=0— without it afetch/pull/pushneeding credentials blocks forever waiting on input that will never arrive, because output is redirected and no terminal is attached. The only mitigation left was a timeout, turning a clean "auth required" failure into an opaque hang-then-cancel.GIT_ASKPASS/SSH_ASKPASS— the supported way to supply credentials to a subprocess without putting them on a command line where any process listing can read them.LC_ALL=C— forces stable, machine-parseable output. Its absence is silent: parsing works on the developer's machine and fails only for users with a localized environment.Approach
One new property on the
CommandOptionsrecord from #43 — no new overloads, which is what the options object was for:The entries are an overlay, not a replacement: a name not listed keeps whatever the caller had. A
nullvalue removes a variable, matchingProcessStartInfo.Environmentsemantics. Leaving the propertynullpreserves today's behaviour exactly.Elevation forces
UseShellExecute, which has nowhere to carry an environment. Rather than letProcess.Startfail with a message mentioning neither setting — or silently drop variables a caller may be relying on for credentials — combining the two throwsArgumentExceptionup front.Testing
ExecuteAsyncShouldSetAnEnvironmentVariableForTheChildProcessExecuteAsyncShouldOverrideAnInheritedEnvironmentVariableExecuteAsyncShouldRemoveAnInheritedEnvironmentVariableWhenTheValueIsNull— asserts the inherited value did not reach the child, since an unset variable prints differently incmdandshExecuteAsyncShouldInheritTheEnvironmentWhenNoVariablesAreGiven— pins that an unset overlay leaves previous behaviour untouchedExecuteAsyncShouldRejectEnvironmentVariablesCombinedWithElevationEach test uses a variable name derived from its own method name, since the host environment is process-wide and tests run in parallel.
Full suite: 32 passed, 2 skipped (elevated tests self-skip to avoid a UAC prompt). Builds clean across all eight target frameworks —
ProcessStartInfo.Environmentis available onnetstandard2.0, so no conditional compilation was needed.🤖 Generated with Claude Code
https://claude.ai/code/session_01LwKTWcmxe5mh6DsLRj5NGQ