Compare commits

...
3 Commits
Author SHA1 Message Date
Thanniru Sai Teja cd84623ab2 [Perf] Optimize nvm_tree_contains_path with in-memory POSIX parent-walk
Tests: alpine / fast arm64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, sh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, sh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.15, zsh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, bash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, dash) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, sh) (push) Canceled after 0s
Tests: alpine / fast x64 (alpine 3.19, zsh) (push) Canceled after 0s
Tests: installation_node / installation_node (bash) (push) Canceled after 0s
Tests: installation_node / installation_node (bash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (dash) (push) Canceled after 0s
Tests: installation_node / installation_node (dash, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (sh) (push) Canceled after 0s
Tests: installation_node / installation_node (sh, without curl) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh) (push) Canceled after 0s
Tests: installation_node / installation_node (zsh, without curl) (push) Canceled after 0s
Tests: xenial / xenial (bash) (push) Canceled after 0s
Tests: xenial / xenial (dash) (push) Canceled after 0s
Tests: xenial / xenial (sh) (push) Canceled after 0s
Tests: xenial / xenial (zsh) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-24.04) (push) Canceled after 0s
Code scanning - action / CodeQL-Build (push) Canceled after 0s
Tests: `nvm install-latest-npm` / matrix (push) Canceled after 0s
Tests: linting / eclint (push) Canceled after 0s
Tests: linting / dockerfile_lint (push) Canceled after 0s
Tests: linting / doctoc (push) Canceled after 0s
Tests: linting / test_naming (push) Canceled after 0s
Tests: linting / check_exec (push) Canceled after 0s
Tests: nvm install with set -e / matrix (push) Canceled after 0s
Tests: release process / release (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Canceled after 0s
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Canceled after 0s
Tests: alpine / fast arm64 (alpine 3, bash) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v22.21.1) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3, node v24.9.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3, node v22.12.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v10.24.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.10, node v8.17.0) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.12, node v12.22.12) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.15, node v14.21.3) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.16, node v16.20.2) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.18, node v18.20.4) (push) Canceled after 0s
Tests: alpine / musl-binary arm64 (alpine 3.20, node v20.20.1) (push) Canceled after 0s
Tests: alpine / musl-binary x64 (alpine 3.20, node v20.18.1) (push) Canceled after 0s
Tests: installation_iojs / actually compile io.js from source (gcc 4.9 container) (push) Canceled after 0s
Tests: fast / fast (bash, gawk) (push) Canceled after 0s
Tests: fast / fast (dash, gawk) (push) Canceled after 0s
Tests: fast / fast (sh, gawk) (push) Canceled after 0s
Tests: fast / fast (zsh, gawk) (push) Canceled after 0s
Tests: fast / fast (bash, mawk) (push) Canceled after 0s
Tests: fast / fast (dash, mawk) (push) Canceled after 0s
Tests: fast / fast (sh, mawk) (push) Canceled after 0s
Tests: fast / fast (zsh, mawk) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (bash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (dash) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (sh) (push) Canceled after 0s
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Canceled after 0s
urchin tests / tests (bash, install_script) (push) Canceled after 0s
urchin tests / tests (bash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (bash, slow) (push) Canceled after 0s
urchin tests / tests (bash, sourcing) (push) Canceled after 0s
urchin tests / tests (dash, installation_iojs) (push) Canceled after 0s
urchin tests / tests (dash, slow) (push) Canceled after 0s
urchin tests / tests (dash, sourcing) (push) Canceled after 0s
urchin tests / tests (sh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (sh, slow) (push) Canceled after 0s
urchin tests / tests (sh, sourcing) (push) Canceled after 0s
urchin tests / tests (zsh, installation_iojs) (push) Canceled after 0s
urchin tests / tests (zsh, slow) (push) Canceled after 0s
urchin tests / tests (zsh, sourcing) (push) Canceled after 0s
update readme TOC / update readme TOC (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Canceled after 0s
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Canceled after 0s
Tests on Windows: `nvm install` / Cygwin nvm install (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-12) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian-13) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-24.04) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine-3.23) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.17) (push) Canceled after 0s
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine-3.23) (push) Canceled after 0s
Tests: linting / all linting (push) Canceled after 0s
Tests: fast / all fast tests (push) Canceled after 0s
Tests: installation_iojs / all installation_iojs tests (push) Canceled after 0s
Tests: installation_node / all installation_node tests (push) Canceled after 0s
Tests: xenial / all xenial tests (push) Canceled after 0s
Tests on Windows: `nvm install` / tests, on windows (push) Canceled after 0s
latest-npm.yml / nvm install-latest-npm (${{ fromJson(needs.matrix.outputs.latest) }}) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.10) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (0.12) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.16) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (14.17) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (20.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (21) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.4) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.5) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (4.6) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (5.9) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (6.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.0) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.1) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (9.2) (push) Canceled after 0s
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s
nvm-install-test.yml / test (no nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 1 shlvl) (push) Canceled after 0s
nvm-install-test.yml / test (nvmrc, ${{ fromJson(needs.matrix.outputs.matrix) }}, 2 shlvls) (push) Canceled after 0s
Tests: nvm install with set -e / finisher (push) Canceled after 0s
Tests: shellcheck / shellcheck (push) Canceled after 0s
Tests: alpine / all alpine tests (push) Canceled after 0s
urchin tests / all test suites, all shells (push) Canceled after 0s
Replace looping subshell process forks (dirname)
in nvm_tree_contains_path with case-guarded in-memory POSIX parameter expansion () and exact string equality comparisons.

Ensures literal string matching for glob metacharacters (*, ?, [])
and full zsh compatibility across all platforms.
2026-09-03 12:24:16 +05:30
Jordan Harband e361b93e4b [Fix] nvm use: do not clobber man's default search path
`man` consults its own configured search path only when MANPATH holds an empty entry;
a list without one replaces the default outright.
`nvm use` produced exactly that,
so activating a version could hide every system man page.

Contribute the empty entry as a trailing one,
so that nvm's directory keeps precedence over the system's,
and only when the list has none already,
so that repeated `nvm use` calls are idempotent and an empty entry the user placed stays where they put it.

The `$(manpath)` snapshot this replaces went stale the moment man's configuration changed,
and cost a subprocess per `nvm use`.
It was also dead: `local MANPATH` scoped the assignment to `nvm()`,
so `export` did not outlive the call and MANPATH went untouched whenever it started out unset.
Only ksh, where `local` is not a builtin, ever ran it.

`nvm deactivate` now unsets MANPATH where nvm's was the only real entry,
rather than leaving a bare `:` behind.

Reported and diagnosed by @al0ksar in #3890, which used a leading empty entry instead.
That one accrues one more colon on every `nvm use`,
which `nvm deactivate` then leaves behind,
and it loses to the system's man pages wherever nvm's bin directory is not first on PATH.

Supersedes #2077.

Refs #3890
Refs #2077
2026-09-08 11:01:03 -07:00
Jordan Harband a5ff3a32f4 [actions] WSL: pin every distribution, and test the newest of each line
The Ubuntu entries were pinned but `Debian` and `Alpine` were floating
aliases, so what those jobs tested drifted whenever the action updated.

Every line now carries a pin and the newest release setup-wsl offers for
it: Debian 12 and 13, Ubuntu 18.04, 20.04 and 24.04, Alpine 3.17 and 3.23.
`Alpine-3.17` is the image the unofficial jobs already ran, named
explicitly. Debian's pin is 12 rather than 11 because `Debian` and
`Debian-11` share a floating `aka.ms/wsl-debian-gnulinux` redirect and so
cannot be held still at all, where `Debian-12` is an immutable
salsa.debian.org artifact. The Debian-only steps key off `startsWith`, so
both Debian entries take the same path and moving a pin will not strand them.

There is no floating "newest" name to use instead: `kali-linux` is the only
unversioned distribution left, and setup-wsl's own CI disables
`additional-packages` on it. The newest only moves when the action's major
does, so the `uses:` ref is the thing to keep current.

Which is the other half of this: move that ref from v6 to v7. v6 is a dead
major, five months stale at v6.1.0 with no v6.2.0 and v7.0.0 tagged the next
day, so new distributions will only ever appear on v7 and later. v7's only
removals are the deprecated bare `Debian` and `Alpine`, which pinning has
already stopped using, and every name here is valid on both. It also drops
the Node.js 20 deprecation warning each WSL job currently emits, and it
tightens two pins that v6 left floating: Ubuntu 20.04 moves from
`aka.ms/wslubuntu2004` to a 20.04.6 image on releases.ubuntu.com, and 24.04
to a 24.04.4 one. Six of the seven platforms are now immutable artifacts;
Ubuntu 18.04 predates the format and still redirects through aka.ms.

Choosing a supported Debian also settles the 404s that had been failing
every Debian job: bullseye left LTS on 2026-08-31 and its security suite is
between homes, with `security.debian.org` still publishing an index whose
pool is being pruned and `archive.debian.org` carrying no `debian-security`
for bullseye yet. bookworm is on live mirrors, so `ca-certificates` is
current again, which matters for a job whose whole purpose is to fetch nvm
and node over TLS.

To keep a pin working once its release ages out in turn, derive sources.list
from the image's own codename and list every layout a release passes through:
main and security move to the archive on separate schedules, and the security
suite is renamed to `<codename>/updates` on the way. `apt-get update`
discards whichever entries 404, and where an index outlives its pool we fall
back once to main alone. Debian 13 moved to deb822, so clear both formats
first and leave what we write as the only thing apt reads.

Drop the blanket `apt-get upgrade` with it: it fetched 77 packages the test
never uses, and `apt-get install` already takes the newest version any
working mirror offers.
2026-09-08 11:01:02 -07:00
6 changed files with 188 additions and 33 deletions
+54 -16
View File
@@ -107,10 +107,15 @@ jobs:
strategy:
fail-fast: false
matrix:
# each line gets a pin, plus the newest setup-wsl offers for it; the
# newest only moves when the action's major does, so bumping the `uses:`
# ref below is what keeps this current
wsl-distrib:
- Debian
# - Alpine # fails
- Debian-12
- Debian-13
# - Alpine-3.17 # fails
- Ubuntu-20.04
- Ubuntu-24.04
- Ubuntu-18.04
npm-node-version:
- '--lts'
@@ -128,31 +133,57 @@ jobs:
- wsl-distrib: Ubuntu-18.04
npm-node-version: '18'
# node v24+ doesn't work on WSL1 (exec format error)
- wsl-distrib: Debian
- wsl-distrib: Debian-12
npm-node-version: '--lts'
- wsl-distrib: Debian-13
npm-node-version: '--lts'
- wsl-distrib: Ubuntu-20.04
npm-node-version: '--lts'
- wsl-distrib: Ubuntu-24.04
npm-node-version: '--lts'
method:
- ''
- 'script'
steps:
# For Ubuntu: install with packages directly
- if: matrix.wsl-distrib != 'Debian'
uses: Vampire/setup-wsl@v6
- if: ${{ !startsWith(matrix.wsl-distrib, 'Debian') }}
uses: Vampire/setup-wsl@v7
with:
distribution: ${{ matrix.wsl-distrib }}
additional-packages: bash git curl ca-certificates wget
# For Debian: install without packages first (apt-get update fails due to stale sources.list)
# For Debian, install without packages: `additional-packages` would run
# `apt-get update` before we get to fix up sources.list
# see https://github.com/Vampire/setup-wsl/issues/76
- if: matrix.wsl-distrib == 'Debian'
uses: Vampire/setup-wsl@v6
- if: ${{ startsWith(matrix.wsl-distrib, 'Debian') }}
uses: Vampire/setup-wsl@v7
with:
distribution: ${{ matrix.wsl-distrib }}
- if: matrix.wsl-distrib == 'Debian'
# Debian's mirror layout shifts as a release ages out of LTS: main moves to
# archive.debian.org, and the security suite is both renamed and moved, on
# its own schedule. Offer every layout and let `apt-get update` discard the
# ones that 404, so this needs no edits as the image's release ages.
- if: ${{ startsWith(matrix.wsl-distrib, 'Debian') }}
name: 'Point apt at whichever mirrors still carry this release'
shell: 'wsl-bash {0}'
run: 'sed -i s/ftp.debian.org/archive.debian.org/ /etc/apt/sources.list'
- if: matrix.wsl-distrib == 'Debian'
run: |
codename="$(. /etc/os-release && printf '%s' "${VERSION_CODENAME-}")"
if [ -z "${codename}" ]; then
echo 'no VERSION_CODENAME in /etc/os-release' >&2
exit 1
fi
# Debian 13 moved to deb822; drop both formats so what we write is the
# only thing apt reads, whichever release is pinned
rm -f /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources
{
echo "deb http://deb.debian.org/debian ${codename} main"
echo "deb http://archive.debian.org/debian ${codename} main"
echo "deb http://security.debian.org/debian-security ${codename}-security main"
echo "deb http://archive.debian.org/debian-security ${codename}-security main"
echo "deb http://archive.debian.org/debian-security ${codename}/updates main"
} >/etc/apt/sources.list
cat /etc/apt/sources.list
- if: ${{ startsWith(matrix.wsl-distrib, 'Debian') }}
name: 'Install packages with retries'
shell: 'wsl-bash {0}'
run: |
@@ -173,9 +204,15 @@ jobs:
}
done
}
retry apt-get update
retry apt-get upgrade --yes
retry apt-get install --yes bash git curl ca-certificates wget
packages=(bash git curl ca-certificates wget)
retry apt-get update || true
if ! retry apt-get install --yes "${packages[@]}"; then
# a security index can outlive the pool objects it advertises, which
# no retry resolves; main is complete once a release is archived
sed -i '/debian-security/d' /etc/apt/sources.list
retry apt-get update || true
retry apt-get install --yes "${packages[@]}"
fi
- name: Retrieve nvm on WSL
run: |
@@ -204,7 +241,8 @@ jobs:
fail-fast: false
matrix:
wsl-distrib:
- Alpine
- Alpine-3.17
- Alpine-3.23
npm-node-version:
- '--lts'
- '21'
@@ -218,7 +256,7 @@ jobs:
- ''
- 'script'
steps:
- uses: Vampire/setup-wsl@v6
- uses: Vampire/setup-wsl@v7
with:
distribution: ${{ matrix.wsl-distrib }}
additional-packages: bash git curl ca-certificates wget
+1 -1
View File
@@ -870,7 +870,7 @@ nvm exposes the following environment variables:
- `NVM_CD_FLAGS` - used to maintain compatibility with zsh.
- `NVM_RC_VERSION` - version from .nvmrc file if being used.
Additionally, nvm modifies `PATH`, and, if present, `MANPATH` and `NODE_PATH` when changing versions.
Additionally, nvm modifies `PATH` when changing versions, along with `MANPATH` wherever a `manpath` command exists, and `NODE_PATH`, if present.
The following environment variables can be set to configure `nvm install`:
+44 -16
View File
@@ -547,6 +547,9 @@ else
fi
unset NVM_SCRIPT_SOURCE 2>/dev/null
# Performs pure in-memory POSIX path containment checking without subshell process forks.
# Uses case-guarded ${pathdir%/*} for parent-walk and exact string equality (=) to ensure literal matching
# for directory names containing glob metacharacters (*, ?, []) across all shells including zsh.
nvm_tree_contains_path() {
local tree
tree="${1-}"
@@ -558,16 +561,36 @@ nvm_tree_contains_path() {
return 2
fi
local previous_pathdir
previous_pathdir="${node_path}"
local pathdir
pathdir=$(dirname "${previous_pathdir}")
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
[ "${pathdir}" != "${tree}" ] && [ "${pathdir}" != "${previous_pathdir}" ]; do
previous_pathdir="${pathdir}"
pathdir=$(dirname "${previous_pathdir}")
local clean_tree
clean_tree="${tree}"
# Strip trailing slashes in shell memory (e.g., "dir//" -> "dir")
while [ "${clean_tree}" != "${clean_tree%/}" ]; do
clean_tree="${clean_tree%/}"
done
[ "${pathdir}" = "${tree}" ]
if [ -z "${clean_tree}" ]; then
clean_tree='/'
fi
# Pure in-memory POSIX parent-walk using parameter expansion instead of subshell dirname forks.
# Uses literal string equality [ "${pathdir}" = "${clean_tree}" ] to prevent glob expansion bugs.
local pathdir
pathdir="${node_path}"
while [ "${pathdir}" != '' ] && [ "${pathdir}" != '.' ] && [ "${pathdir}" != '/' ] &&
[ "${pathdir}" != "${clean_tree}" ]; do
case "${pathdir}" in
*/*)
pathdir="${pathdir%/*}"
if [ -z "${pathdir}" ]; then
pathdir='/'
fi
;;
*)
break
;;
esac
done
[ "${pathdir}" = "${clean_tree}" ]
}
nvm_find_project_dir() {
@@ -4257,7 +4280,11 @@ nvm() {
nvm_err "Could not find ${NVM_DIR}/*/share/man in \${MANPATH}"
fi
else
export MANPATH="${NEWPATH}"
# `man` treats both of these as unset anyway, so leave nothing behind
case "${NEWPATH}" in
'' | ':') unset MANPATH ;;
*) export MANPATH="${NEWPATH}" ;;
esac
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_echo "${NVM_DIR}/*/share/man removed from \${MANPATH}"
fi
@@ -4380,12 +4407,13 @@ nvm() {
# Change current version
PATH="$(nvm_change_path "${PATH}" "/bin" "${NVM_VERSION_DIR}")"
if nvm_has manpath; then
if [ -z "${MANPATH-}" ]; then
local MANPATH
MANPATH=$(manpath)
fi
# Change current version
MANPATH="$(nvm_change_path "${MANPATH}" "/share/man" "${NVM_VERSION_DIR}")"
MANPATH="$(nvm_change_path "${MANPATH-}" "/share/man" "${NVM_VERSION_DIR}")"
# `man` consults its configured default path only where the list has an
# empty entry; a trailing one keeps nvm's directory ahead of it
case "${MANPATH}" in
:* | *::* | *:) ;;
*) MANPATH="${MANPATH}:" ;;
esac
export MANPATH
fi
export PATH
@@ -0,0 +1,68 @@
#!/bin/sh
set -e
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../.. && pwd)"
# `--delete-prefix` covers only the npmrc files, so an inherited prefix in the
# environment would still abort `nvm use`
unset PREFIX npm_config_prefix NPM_CONFIG_PREFIX
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
# the block under test is gated on `nvm_has manpath`, and the Alpine CI images
# ship no `manpath`; the output is recognizable so that a reintroduced
# `$(manpath)` call fails the assertions instead of passing vacuously
manpath() {
echo '/usr/share/man'
}
make_fake_node v0.10.2
make_fake_node v0.10.3
MAN_2="$(nvm_version_path v0.10.2)/share/man"
MAN_3="$(nvm_version_path v0.10.3)/share/man"
# nvm has to contribute the empty entry itself when there is nothing to preserve
unset MANPATH
nvm use --delete-prefix v0.10.2 --silent || die "Failed to activate v0.10.2"
[ "${MANPATH}" = "${MAN_2}:" ] || die "MANPATH should be '${MAN_2}:'; got '${MANPATH}'"
nvm deactivate --silent || die "Failed to deactivate v0.10.2"
[ -z "${MANPATH-}" ] || die "MANPATH should be unset again; got '${MANPATH}'"
# nvm's entry first, the empty entry last: the reverse of what a leading empty
# entry produces
MANPATH='/opt/foo/man'
nvm use --delete-prefix v0.10.2 --silent || die "Failed to activate v0.10.2"
[ "${MANPATH}" = "${MAN_2}:/opt/foo/man:" ] || die "MANPATH should be '${MAN_2}:/opt/foo/man:'; got '${MANPATH}'"
# switching versions replaces nvm's entry without accruing more empty ones
nvm use --delete-prefix v0.10.3 --silent || die "Failed to activate v0.10.3"
[ "${MANPATH}" = "${MAN_3}:/opt/foo/man:" ] || die "MANPATH should be '${MAN_3}:/opt/foo/man:'; got '${MANPATH}'"
nvm use --delete-prefix v0.10.2 --silent || die "Failed to reactivate v0.10.2"
[ "${MANPATH}" = "${MAN_2}:/opt/foo/man:" ] || die "MANPATH should be '${MAN_2}:/opt/foo/man:'; got '${MANPATH}'"
nvm deactivate --silent || die "Failed to deactivate v0.10.2"
[ "${MANPATH}" = '/opt/foo/man:' ] || die "MANPATH should be '/opt/foo/man:'; got '${MANPATH}'"
# a value with no empty entry at all still deactivates to nothing
MANPATH="${MAN_2}"
nvm deactivate --silent || die "Failed to deactivate v0.10.2"
[ -z "${MANPATH-}" ] || die "MANPATH should be unset again; got '${MANPATH}'"
# an empty entry the user placed themselves stays where they put it
for TEST_MANPATH in ':/opt/foo/man' '/opt/foo/man:' '/a/man::/b/man'; do
MANPATH="${TEST_MANPATH}"
nvm use --delete-prefix v0.10.2 --silent || die "Failed to activate v0.10.2 with MANPATH '${TEST_MANPATH}'"
[ "${MANPATH}" = "${MAN_2}:${TEST_MANPATH}" ] || die "MANPATH should be '${MAN_2}:${TEST_MANPATH}'; got '${MANPATH}'"
nvm deactivate --silent || die "Failed to deactivate v0.10.2 with MANPATH '${TEST_MANPATH}'"
[ "${MANPATH}" = "${TEST_MANPATH}" ] || die "MANPATH should be '${TEST_MANPATH}'; got '${MANPATH}'"
done
+14
View File
@@ -44,6 +44,20 @@ NEW_PATH=`nvm_change_path "$EMPTY_PATH" "/bin" "$NVM_DIR/v0.1.2"`
[ "$NEW_PATH" = "$NVM_DIR/v0.1.2/bin" ] || die "Not correctly prepended: $NEW_PATH "
# empty entries select `man`'s own search path, so they have to survive intact
MAN_PATH_WITH_EMPTY_ENTRIES=/opt/foo/man::/opt/bar/man:
# New version dir
NEW_PATH=`nvm_change_path "$MAN_PATH_WITH_EMPTY_ENTRIES" "/share/man" "$NVM_DIR/versions/node/v7.1.0"`
[ "$NEW_PATH" = "$NVM_DIR/versions/node/v7.1.0/share/man:$MAN_PATH_WITH_EMPTY_ENTRIES" ] || die "Not correctly prepended: $NEW_PATH "
# Replacing an existing version dir
NEW_PATH=`nvm_change_path "$NVM_DIR/versions/node/v4.5.0/share/man::/opt/bar/man:" "/share/man" "$NVM_DIR/versions/node/v7.1.0"`
[ "$NEW_PATH" = "$NVM_DIR/versions/node/v7.1.0/share/man::/opt/bar/man:" ] || die "Not correctly changed: $NEW_PATH "
# https://github.com/nvm-sh/nvm/issues/1652#issuecomment-342571223
MAC_OS_NESTED_SESSION_PATH=/usr/bin:/usr/local/bin:$NVM_DIR/versions/node/v4.5.0/bin
@@ -29,4 +29,11 @@ nvm_tree_contains_path tmp2 tmp2/node || die '"tmp2" should contain "tmp2/node"'
nvm_tree_contains_path tmp2 tmp/node && die '"tmp2" should not contain "tmp/node"'
nvm_tree_contains_path tmp/ tmp/node || die '"tmp/" should contain "tmp/node"'
nvm_tree_contains_path tmp// tmp/node || die '"tmp//" should contain "tmp/node"'
nvm_tree_contains_path / /tmp/node || die '"/" should contain "/tmp/node"'
nvm_tree_contains_path "tmp[glob]" "tmp[glob]/node" || die '"tmp[glob]" should contain "tmp[glob]/node"'
nvm_tree_contains_path "tmp" "tmp[glob]/node" && die '"tmp" should not contain "tmp[glob]/node"'
cleanup