Skip to content

feat(nodeenv): write the posix activate on Windows for git-bash - #409

Merged
ekalinin merged 4 commits into
masterfrom
feat/git-bash-activate
Sep 21, 2026
Merged

ekalinin merged 4 commits into
masterfrom
feat/git-bash-activate

Conversation

@ekalinin

Copy link
Copy Markdown
Owner

Closes #226.

On Windows nodeenv wrote only activate.bat, deactivate.bat and
Activate.ps1, so git-bash and the other posix shells available there had
nothing to source. Python's venv keeps its bash activate in
scripts/common/ and installs it on every platform; this does the same.

The script needed two Windows adjustments

  • npm keeps the global modules next to node.exe, in Scripts/node_modules,
    not in lib/node_modules, and its prefix is the directory holding
    node.exe - so NODE_PATH and NPM_CONFIG_PREFIX point there.
  • node.exe is a native binary and cannot read the /c/... paths a Windows
    shell hands out, so both variables are converted back with cygpath -w
    while $PATH stays posix, since that one is read by the shell itself.
    venv solves the same problem the same way.

The "do not call this file directly" guard now matches */Scripts/activate
too, and the $PATH line builds the .bin directory from __MOD_NAME__
instead of a hardcoded lib/node_modules - on posix both render exactly as
before.

Tests

tests/test_install_activate.py gets 8 tests that fake is_WIN, so the
Scripts/ layout is checked from any host: the set of files written, the
$PATH line, the native paths, sh -n over the generated script, the direct
call guard, and -p appending to the Scripts/activate that venv already
wrote there instead of replacing it.

Behaviour on a real Windows host is covered by test_smoke_git_bash, run by
a new git-bash CI job: shell: bash on a windows runner is git-bash. It
builds an environment, sources Scripts/activate and asserts that
process.execPath and npm root -g both point inside it - the second one
fails if the cygpath conversion did not happen.

Not in scope

  • activate.fish is still posix-only, there is no native fish on Windows.
  • The non-BASH_SOURCE fallback in ACTIVATE_SH still embeds the native
    C:\... path, which would break $PATH if a non-bash shell sourced it on
    Windows. git-bash ships bash as sh, so the case from the issue is covered.
  • set_predeactivate_hook() writes .bat/.ps1 hooks only on Windows; a
    posix predeactivate for git-bash is a separate question.

On Windows only activate.bat, deactivate.bat and Activate.ps1 were
written, so git-bash and the other posix shells there had nothing to
source. Python's venv treats its bash activate as "common" and installs
it on every platform; do the same.

The script itself needs two Windows adjustments: node.exe keeps the
global modules next to itself, in Scripts/node_modules rather than
lib/node_modules, and it cannot read the /c/... paths a Windows shell
hands out, so NODE_PATH and NPM_CONFIG_PREFIX are converted back with
cygpath while $PATH stays posix.

A new CI job runs the activation under `shell: bash` on a windows
runner, which is git-bash.

#226
The first CI run of the new job failed with a bare exit 1 and no
diagnostic: the probe ran through `bash -c` with the script and the
environment path as arguments, so the quoting rules of two command line
parsers sat between the test and what the shell ran, and stderr was not
captured at all. It now writes the probe to a file, traces it with
`set -x` and puts both streams into the assertion message.

The direct call guard matches on $0, which a shell reports in the form
it was given; the test was passing the native `C:\...` path, which no
posix shell would produce.
`bash` on PATH is C:\Windows\System32\bash.exe, the WSL launcher: on a
runner without a distribution it answers "Windows Subsystem for Linux
has no installed distributions" in UTF-16 and exits 1, which is what
the job was reporting. Look git-bash up next to git instead.
Looking git-bash up next to git.exe missed: on PATH inside git-bash git
is Git/mingw64/bin/git.exe, and there is no bash.exe beside it. The job
already runs in the right shell, so it now passes $BASH to the test,
which keeps a PATH lookup that skips the System32 launcher for runs
outside CI.
@ekalinin
ekalinin merged commit f771a61 into master Sep 21, 2026
44 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.

Git-Bash Support

1 participant