Compare commits

...
40 Commits
Author SHA1 Message Date
Jordan Harband b6cf55f6ad v0.40.6 2026-07-15 14:09:54 -07:00
Jordan Harband 9275c5badd [Robustness] reject unsafe LTS alias names from a mirror's index.tab
A mirror-supplied LTS codename (field 10 of index.tab) was used verbatim as an alias filename,
so a hostile codename such as `../../../.bashrc` could make nvm_make_alias write outside $NVM_DIR/alias
- with the default layout, into shell startup files.
Constrain remote codenames to safe filename characters at ingestion in nvm_ls_remote_index_tab,
and reject any `..` path component in nvm_make_alias as a backstop for every caller.
2026-07-15 13:46:52 -07:00
Jordan Harband 882ed79ece [Docs] threat model: document the mirror payload/metadata trust boundary
Payloads
(binaries, plus source tarballs that nvm compiles and runs at install time) are trusted by construction,
since nvm exists to build and run them;
parsed metadata (index.tab, SHASUMS, LTS codenames) is not,
and must never reach a command evaluator,
an awk/sed program body,
or an unvalidated filesystem path.
This records why the existing version-string and checksum hardening exists,
and scopes a malicious payload from a configured mirror as out of scope:
no privilege boundary is crossed.
2026-07-15 13:44:04 -07:00
Jordan Harband d83da5d75b [actions] add tests-alpine: a green fast suite and a musl-binary regression matrix
The full suite cannot run on Alpine: the install-based suites pin ancient Node (0.10.x, io.js) that has no musl binary and cannot source-compile on musl.
Run the fast unit suite instead (mirroring the ubuntu runner: non-root via su-exec, passwordless sudo, a PTY, no system node), plus a binary-only regression matrix that installs every (Alpine, Node) pair with a real unofficial musl binary via `nvm install -b`: x64 back to node 8.17.0 on old Alpine, arm64 at the v20.20.1/v22.21.1/v24.9.0 floors on modern Alpine.
2026-07-14 23:18:07 -07:00
Jordan Harband 438009f54e [Tests] make the fast suite pass on Alpine
`nvm_get_arch`: skip the smartos arm64/armv8l cases, which have no uname mock and fall through to the real host (adding a musl suffix on Alpine).
`nvm_get_arch_unofficial`: skip the glibc chroot (fixed /lib64 loader, sudo); the musl mapping is already covered by the `nvm_get_arch alpine` test.
`nvm_install_no_progress_bar`: skip below the musl floor, since v0.12.18 has no musl binary and hardcodes the glibc tarball URL.
2026-07-14 23:17:01 -07:00
Jordan Harband f1e7a84cb5 [Robustness] avoid a set -u error when $_ is unset
Sourcing nvm.sh under `set -u` on a POSIX shell that leaves `$_` unset (e.g. busybox ash or dash on Alpine, where the parent shell does not export it) aborted at `NVM_SCRIPT_SOURCE="$_"`.
Default to empty; the only consumer already falls back to `$0`.
2026-07-14 23:16:39 -07:00
Jordan Harband 86c937436d [Robustness] nvm_get_arch: only apply the Alpine musl suffix when the OS is linux
The `/etc/alpine-release` check applied the -musl suffix regardless of the resolved OS.
In practice Alpine is always linux, so this is behavior-neutral, but it also makes the `nvm_get_arch` unit test hermetic: its mocked smartos/osx cases no longer pick up a real host's Alpine marker.
2026-07-14 23:10:33 -07:00
Jesse ZhuandJordan Harband ce157c1171 [Fix] support arm64-musl on Alpine Linux
Node.js unofficial-builds publishes linux-arm64-musl binaries since v20.20.1 / v22.21.1 / v24+.
Map NVM_ARCH=arm64 to arm64-musl on Alpine so `nvm install`
resolves to the correct tarball instead of the glibc-linked arm64 build that won't run against musl.

[Tests] `nvm_get_arch`: expect arm64-musl on Alpine

Co-authored-by: Jesse Zhu <jesse@itjesse.com>
Co-authored-by: Jordan Harband <ljharb@gmail.com>
2026-05-23 01:35:12 +09:00
Jordan Harband c7d5d7748b [Tests] run every remaining test file: exec bits, fixes; add check-exec to CI
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: linting / check_exec (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_iojs / actually compile io.js from source (gcc 4.9 container) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
urchin only executes test files that have the executable bit, silently skipping the rest,
and `npm run test:check-exec` would catch non-executable ones, but no workflow ran it -
so several test files have never actually run.
Make all of them executable, and fix the ones that were broken:
- the io.js source-install tests, skipped since 2016: io.js requires python 2 and gcc <= 5,
so they now skip on toolchains that can not compile it,
and a new gcc:4.9-container CI job runs them unmodified -
resolving, downloading, checksumming, and compiling io.js for real.
New `fake source` variants exercise nvm's source pipeline everywhere -
cache lookup, offline resolution, extraction, configure, make, make install, activation -
via a tiny fake source tree seeded into the download cache and installed with `--offline`.
Also strengthen the `nvm run | grep` assertions with `--silent`,
since the version banner used to satisfy the grep even when the built binary could not run,
and give the final assertions the `die` they always meant to call.
- `nvm uninstall ... incorrect file permissions fails nicely`, parked in 2025 as failing:
`sudo npm` resets PATH, so node 5's npm crashed under the system node.
The permissions check only trips on files that are neither writable nor self-owned,
and that precondition only needs `sudo touch` - not npm, jspm, or the network -
so use that, against a fake installed version,
and skip only where passwordless sudo does not exist.
- `nvm install --offline`: `nvm ls | tail -1` always grabbed an alias line, never a version;
use `nvm_ls` and skip its trailing `system <version>` line.
- `nvm exec ... help should not parse`: in a BRE, `[options]` is a bracket expression,
so the grep could never match node's literal `Usage: node [options]` output.
- `nvm use ... nvmrc containing not installed version`: current output once again matches its expectations verbatim; no changes needed.

Rewrite `test:check-exec` in POSIX sh - npm runs scripts with /bin/sh, which is dash on Ubuntu,
where the previous `[[`/`$'\n'` bashisms would break;
match by extension, so that filenames containing dots can not dodge the check;
and disable git's `core.quotePath` mangling of the non-ASCII test filenames.
Then wire it into the lint workflow.
2026-07-09 22:40:07 -07:00
Jordan Harband 4e48294bd6 [Fix] nvm_ls_cached: include source-cached and io.js artifacts
`--offline` version resolution could only see cached node binaries:
`nvm_ls_cached` listed `.cache/bin` with a `node-` prefix filter,
so cached source tarballs, and everything io.js, could never resolve offline.
List both cache kinds, for both flavors,
and update the pinned test expectations to match.
2026-07-09 22:35:15 -07:00
Jordan Harband 1a39786c8a [Tests] nvm_offline_version: make it executable; pin nvm_ls_cached cache visibility
The test was born without its executable bit,
and urchin silently skips non-executable files, so it has never run.
Also pin what `nvm_ls_cached` can currently see:
only bin-cached node artifacts - bin-cached io.js, and src-cached anything,
are invisible to it, and thus to `--offline` version resolution.
2026-07-09 22:35:15 -07:00
Mathew DodgsonandJordan Harband 3a8b51c46c [Fix] auth header: Add all valid base64 chars to sanitize function
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
2026-05-25 11:14:39 +10:00
Jordan Harband ebada63259 [Tests] aliases: cover the regex-metachar cycle fix; clean up fixtures in teardown
The cycle scenarios all pass with the old grep-based detection too;
the bug the `case`-based detection actually fixes is resolved names interpolated into the grep pattern as regexes,
where resolving axb -> a.b falsely reported ∞ because the pattern `a.b` matches the seen name `axb`.
Pin both directions: the fixed false positive, and a genuine cycle through a metachar name.

Also correct the space-name scenario comment
(the old anchored grep passed that scenario; only token-delimited seen-storage would not),
and register every new fixture name in the suite teardown,
so a mid-test failure can not leak aliases into later tests.
2026-07-09 15:58:41 -07:00
Jake LodwickandJordan Harband 0a9dead76d [Refactor] nvm_alias: one-pass trailing whitespace strip
Replace the per-character trailing-whitespace loop with a one-pass
parameter expansion, per review.
2026-05-05 23:32:58 -04:00
Jake LodwickandJordan Harband 304a22ad59 [Refactor] nvm_alias: use [[:space:]] instead of literal tab
[Tests] `nvm_alias`: add edge-case tests for hostile file content
2026-02-18 14:29:52 -07:00
Jake LodwickandJordan Harband d22bf7f538 [Refactor] nvm_alias, nvm_resolve_alias: use builtins
[Tests] `nvm_alias`, `nvm_resolve_alias`: add edge-case tests

nvm_alias() used a sed/awk pipeline to strip comments and blank lines from alias files that almost always contain a single word.
A while-read loop with parameter expansion does the same filtering more directly.

nvm_resolve_alias() piped nvm_alias through head and tail to extract one line, and used printf/grep for cycle detection.
Parameter expansion and a case statement replace both without the extra plumbing.

All replacements are POSIX (read -r, case, IFS=, parameter expansion).
As a side effect, this also removes 4 external process invocations during shell init.

[Fix] `nvm_resolve_alias`: detect cycles via newline-anchored `case`

The original commit referenced above changed SEEN_ALIASES from `\n`-delimited
storage (interpreted by `printf '%b' | nvm_grep -e "^${name}$"`) to space-
delimited but left the line-anchored grep in place — without newlines in
the haystack the anchored pattern can never match, so cycles never break.

Switch to literal-newline storage and a `case` pattern anchored on those
newlines. Newline anchoring also handles alias names containing spaces,
which token-based patterns false-positive on (e.g. lookup of `bar` matches
substring " bar " inside " foo bar midway " when the chain visits the
multi-token alias `foo bar`).

New test file covers self-loop, multi-hop loop, cycle through a
space-bearing alias name, and a non-cycle through a space-bearing
alias name. Existing `test/fast/Aliases/circular/` fixtures continue
to pass.
2026-02-17 13:44:31 -07:00
Jordan Harband dd61ae4bc8 [Robustness] nvm_alias: explicitly succeed when the alias file is unreadable
The sed/awk pipeline exits with awk's status,
so an existing-but-unreadable alias file produces empty output with status 0 - but only by accident,
alongside sed's read error on stderr.
Make that contract explicit:
a nonzero status here would flip `nvm_ensure_default_set` from "default is already set" to recreating it,
silently overwriting a write-only default alias.
2026-07-09 15:43:56 -07:00
Jordan Harband 59cf9a4ef6 [actions] nvm-install-test: turn the expected v0.40.0 failures green
The two `v0.40.0` + `nvmrc` jobs fail by design (https://github.com/nvm-sh/nvm/issues/3405),
but job-level `continue-on-error` still displays them as failures on every run,
which reads like the contributor broke something.
Tolerate failure only in the steps that exercise the bug, scoped to that matrix combination,
and add a final step that fails the job when the expected failure did not happen -
so those jobs are green exactly when v0.40.0 misbehaves as documented,
and turn red as a signal to remove this handling if v0.40.0 ever starts passing.
This also restores strict failure semantics to the passing `v0.40.0` + `no nvmrc` jobs,
which the job-level `continue-on-error` was needlessly masking.
2026-07-09 17:01:32 -07:00
Jordan Harband 21d33ef04a [Tests] nvm_ls handles hash in pattern: fix cleanup, isolate NVM_DIR, cover the sed path
- `cleanup` unset TEST_DIR before `rm -rf "${TEST_DIR-}"`, so the temp dir (with an executable fake `node`) was never removed,
and urchin executes any executable file it finds under the test dir on the next local run.
- the preexisting `foo#bar` assertions ran against the ambient NVM_DIR;
now that `#` patterns comment-strip to `foo`, a real local alias named `foo` would resolve and break them,
so all assertions now run against an isolated NVM_DIR.
- the multiline content used a full x.y.z version, which takes nvm_ls's explicit-version fast path and never reaches the find/sed pipeline where the newline actually broke sed;
a partial version exercises that path, and matching on "unterminated" covers both the BSD and GNU sed error wordings.
2026-07-08 23:14:23 -07:00
jinhyuk9714andJordan Harband 82315e2b18 [Fix] Parse commented nvmrc content in nvm_ls
Fixes #3761

Signed-off-by: jinhyuk9714 <jinhyuk9714@gmail.com>
2026-06-09 00:21:55 +09:00
Yinan QinandJordan Harband ab77712867 [New] install: add support for loongarch64 architecture 2025-10-25 19:19:05 +08:00
ryenusandJordan Harband 0c1243a7ea [Fix] bypass aliased curl
Closes #2932
2023-01-10 15:32:47 +08:00
Jordan Harband 9142a92cdc [Fix] nvm_download, nvm_get_latest, install: only select a downloader that exists as an executable
`nvm_has` matches shell functions and aliases,
but downloads now run via `command`, which skips them
- a `curl` shell function with no curl binary on the PATH would select the curl path and fail with exit 127,
instead of falling back to an available wget executable.
The new `nvm_has_executable` helper resolves names the same way `command` does, so downloader selection and execution agree.
2026-07-08 13:03:16 -07:00
Jordan Harband 04fef13bdc [Fix] use command to bypass curl/wget shell functions and aliases
zsh (and interactive bash with `expand_aliases`) bakes a preexisting `curl` alias into nvm's function bodies at source time,
and shell functions named `curl`/`wget` shadow the binaries at call time - either one breaks downloads.
Prefixing invocations with `command` bypasses both: here, `nvm_download`'s dispatch, `nvm_curl_version`, `nvm_curl_libz_support`, and the wget branch of `nvm_get_latest`;
the remaining bare `curl` invocations in `nvm_get_latest` and the install script are prefixed in a followup commit.

The tests that previously mocked curl/wget as shell functions now install fake executables on PATH instead,
via a shared `make_fake_curl` helper in `test/common.sh`,
and a new test asserts the bypass.

Refs #2923
2026-07-08 13:02:41 -07:00
Rahul BeniwalandJordan Harband cb0e0ba8ed [Fix] install: use darwin-x64 for all binary on mac for node < v16 2025-11-16 14:48:10 +05:30
Curt J. SampsonandJordan Harband b16fb6ece9 [readme] Docker: build time is "several" minutes, not 8
On my system, even without using local mirrors, the build is only two
minutes, even though I have only a 1 Gbps Internet connection and I'm
half-way across the world in Tokyo.

There probably are still users with much slower Internet connections
where the build could take eight minutes or more, but "several" still
covers that.
2025-09-15 18:06:37 +09:00
Curt J. SampsonandJordan Harband 190cb9458b [readme] Docker: Just say "Ubuntu" (no version) for base image
The base image is updated regularly (it's currently 22.04), and it's
easy to forget to update this readme, so best we simply not repeat
ourselves and instead let people look at `Dockerfile` to see exactly
which version of Ubuntu it's using.
2025-09-15 08:20:51 +00:00
Jordan Harband e2e612e722 [Tests] installation_node: only match top-level global packages
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
2026-07-02 15:49:01 -05:00
Jordan Harband 041a57747a [Tests] installation_node: use a published is-nan version
`is-nan@1.0.0` was published on 2014-07-05 and unpublished minutes later
(the registry's `time` map still lists it, but `versions` jumps from `0.0.0` to `1.0.1`),
so `npm install -g is-nan@1.0.0` fails with `ETARGET`,
and the regression test added in ce157343 fails deterministically in every shell.

See https://github.com/nvm-sh/nvm/actions/runs/28407118533
2026-07-02 14:35:57 -05:00
Jordan Harband 419ff4efec [actions] update workflows
Tests: fast / fast (sh, mawk) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
2026-06-29 17:33:31 -05:00
Jordan Harband 7a7908ffa1 [Dev Deps] update doctoc, semver 2026-06-29 16:43:55 -05:00
Jordan Harband ce15734300 [Fix] nvm install: migrate packages/set alias when target is already installed
When `nvm install <target>` found that `<target>` was already installed,
the post-`nvm use` steps
(`--reinstall-packages-from`, default packages, and `--alias`/`--default`)
were gated on `[ $EXIT_CODE -ne 0 ]`.
Since that branch is only entered when `nvm use` succeeded (EXIT_CODE == 0),
those conditions were always false, so the steps were silently skipped.

The fresh-install branch correctly uses `-eq 0`;
mirror that here so `--reinstall-packages-from` actually migrates global packages
(and the alias/default get set) when the target version already exists.

Includes a regression test covering the already-installed path.

Fixes #3858
2026-06-29 16:39:19 -05:00
Jordan Harband ee4fa818d2 [Docs] document nvm reinstall-packages as a standalone command
The standalone `nvm reinstall-packages <version>`
command can migrate global npm packages between already-installed versions,
but it was only mentioned in `nvm --help`, not in the README.
Add a section covering it.

Refs #3858
2026-06-29 14:51:15 -05:00
Jordan Harband a6ec739430 [Docs] document current and clarify .nvmrc fallback in help/README
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
- Help text for `nvm install`/`use`/`exec`/`run`/`which` now ends with
  "Uses .nvmrc if version is omitted; otherwise errors."
  so it's clear that omitting the version is not a free fallback.
- Help signatures for `use`/`exec`/`run` now show `[current | <version>]`
  to mirror `nvm which` and document that `current` is accepted.
- `nvm current` description now spells out that it resolves via `$PATH`
  and is not affected by `.nvmrc`.
- README: add `current` to the list of special aliases, with the same caveat.
  The `.nvmrc` section now states that `nvm use`/`install`/`which`
  exit with status 127 when neither a version nor an `.nvmrc` resolves,
  notes the (current) `exec`/`run` fallback as undefined behavior,
  and points readers at `current` for the explicit "active node" use case.

Refs #3755
2026-06-10 15:16:24 -07:00
Jordan Harband 718e880890 [Fix] focused error on missing/invalid args for several subcommands
Previously a number of subcommands dumped the entire `nvm --help`
output (~100 lines) when arguments were missing or invalid,
drowning the real error.
Replace each dump with a short,
command-specific usage block that names the expected syntax and points to `nvm --help` for full help.
The exit code (127) is unchanged.

Affected subcommands:
- `nvm install` (no version + no .nvmrc)
- `nvm use`     (version unresolvable)
- `nvm run`     (no version + no .nvmrc)
- `nvm which`   (no version + no .nvmrc)
- `nvm cache`   (unknown subcommand)
- `nvm uninstall`         (wrong arg count)
- `nvm unalias`           (wrong arg count)
- `nvm install-latest-npm` (wrong arg count)
- `nvm reinstall-packages` / `nvm copy-packages` (wrong arg count)

The catch-all unknown-subcommand handler still dumps full help, since
in that case the user has no narrower context to be reminded about.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband ed4dbdfdd5 [Fix] nvm_rc_version: clarify error when no version and no .nvmrc
Previously the message read "No .nvmrc file found",
which obscured the fact that the user also did not pass a version.
The new wording names both halves of the actual problem.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband a9933f77a6 [Fix] nvm exec/nvm run: warn when no version and no .nvmrc
Currently these commands silently fall back to the active node version when neither a version argument nor an `.nvmrc` resolves,
making them invisibly dependent on shell state and impossible to script predictably (see #3755).

Print a stderr deprecation warning in this case (suppressed by `--silent`) and continue with the active node version,
so existing callers keep working.
The follow-up change will turn this into a hard error;
pass `current` explicitly (e.g. `nvm exec current node ...`) to silence the warning and lock in the new behavior now.

Refs #3755
2026-06-10 15:16:23 -07:00
Jordan Harband 7079a5d61c [actions] nodejs.org PR: sync the fork before branching, and surface create-ref errors
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
2026-06-04 14:52:41 -07:00
Jordan Harband 306f04a90a [actions] nodejs.org PR: fix force boolean and grab the latest tag on dispatch
Code scanning - action / CodeQL-Build (push) Has been cancelled
Tests: `nvm install-latest-npm` / nvm install-latest-npm (push) Has been cancelled
Tests: `nvm install-latest-npm` / matrix (push) Has been cancelled
Tests: linting / eclint (push) Has been cancelled
Tests: linting / dockerfile_lint (push) Has been cancelled
Tests: linting / doctoc (push) Has been cancelled
Tests: linting / test_naming (push) Has been cancelled
Tests: linting / all linting (push) Has been cancelled
Tests: nvm install with set -e / matrix (push) Has been cancelled
Tests: nvm install with set -e / test (push) Has been cancelled
Tests: nvm install with set -e / finisher (push) Has been cancelled
Tests: release process / release (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (bash_completion, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (install.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm-exec, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, bash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, dash) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, ksh) (push) Has been cancelled
Tests: shellcheck / shellcheck_matrix (nvm.sh, sh) (push) Has been cancelled
Tests: shellcheck / shellcheck (push) Has been cancelled
Tests: fast / all fast tests (push) Has been cancelled
Tests: fast / fast (bash, gawk) (push) Has been cancelled
Tests: fast / fast (dash, gawk) (push) Has been cancelled
Tests: fast / fast (sh, gawk) (push) Has been cancelled
Tests: fast / fast (zsh, gawk) (push) Has been cancelled
Tests: fast / fast (dash, mawk) (push) Has been cancelled
Tests: fast / fast (sh, mawk) (push) Has been cancelled
Tests: fast / fast (zsh, mawk) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (bash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (dash) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (sh) (push) Has been cancelled
Tests: installation_iojs / installation_iojs without curl (zsh) (push) Has been cancelled
Tests: installation_iojs / all installation_iojs tests (push) Has been cancelled
Tests: installation_node / installation_node (dash) (push) Has been cancelled
Tests: installation_node / installation_node (dash, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (sh) (push) Has been cancelled
Tests: installation_node / installation_node (sh, without curl) (push) Has been cancelled
Tests: installation_node / installation_node (zsh) (push) Has been cancelled
Tests: installation_node / installation_node (zsh, without curl) (push) Has been cancelled
Tests: installation_node / all installation_node tests (push) Has been cancelled
Tests: installation_node / installation_node (bash) (push) Has been cancelled
Tests: installation_node / installation_node (bash, without curl) (push) Has been cancelled
Tests: xenial / xenial (bash) (push) Has been cancelled
Tests: xenial / xenial (dash) (push) Has been cancelled
Tests: xenial / xenial (sh) (push) Has been cancelled
Tests: xenial / xenial (zsh) (push) Has been cancelled
Tests: xenial / all xenial tests (push) Has been cancelled
urchin tests / tests (bash, install_script) (push) Has been cancelled
urchin tests / all test suites, all shells (push) Has been cancelled
urchin tests / tests (bash, installation_iojs) (push) Has been cancelled
urchin tests / tests (bash, slow) (push) Has been cancelled
urchin tests / tests (bash, sourcing) (push) Has been cancelled
urchin tests / tests (dash, slow) (push) Has been cancelled
urchin tests / tests (dash, sourcing) (push) Has been cancelled
urchin tests / tests (sh, installation_iojs) (push) Has been cancelled
urchin tests / tests (sh, slow) (push) Has been cancelled
urchin tests / tests (sh, sourcing) (push) Has been cancelled
urchin tests / tests (zsh, installation_iojs) (push) Has been cancelled
urchin tests / tests (zsh, slow) (push) Has been cancelled
urchin tests / tests (zsh, sourcing) (push) Has been cancelled
update readme TOC / update readme TOC (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS fail prefix nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--default 12) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--lts) (push) Has been cancelled
Tests on Windows: `nvm install` / MSYS nvm install (--no-progress 10) (push) Has been cancelled
Tests on Windows: `nvm install` / Cygwin nvm install (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-18.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Debian) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Ubuntu-20.04) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, --lts, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 11, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 21, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 12, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 14, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 16, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 18, Alpine) (push) Has been cancelled
Tests on Windows: `nvm install` / tests, on windows (push) Has been cancelled
Tests: fast / fast (bash, mawk) (push) Has been cancelled
urchin tests / tests (dash, installation_iojs) (push) Has been cancelled
Tests on Windows: `nvm install` / WSL nvm install (script, 10, Debian) (push) Has been cancelled
The branch-reset step sent `force` as a string via `gh api -f "force=true"`,
which the Git refs API rejects ("not a boolean", HTTP 422), failing the release run.
Use `-F` so it is sent as a boolean.

Also resolve the version from the latest `vX.Y.Z` tag
(via the tags API) rather than `releases/latest`,
so a manual `workflow_dispatch` with no input works even before the GitHub release object for a freshly pushed tag is published.
2026-06-04 09:54:01 -07:00
Jordan Harband 77fca77ddd [actions] fall back to the canonical nvmrc submodule when a fork lacks its own
Upstream's `.gitmodules` uses a relative submodule url (`../nvmrc.git`),
which resolves against the superproject's origin:
on a fork without its own `nvmrc` fork that is `<owner>/nvmrc`,
which 404s and fails `actions/checkout` with `submodules: true`.
Keep `submodules: true` (so a fork's own `nvmrc` is used when present),
but mark checkout `continue-on-error` and, only when it failed,
re-point the submodule at `nvm-sh/nvmrc` and update.
2026-06-04 09:22:04 -07:00
68 changed files with 1874 additions and 233 deletions
+32
View File
@@ -107,3 +107,35 @@ Additionally, the maintainer of a third-party dependency might introduce a vulne
**Recommendation**: Third-party libraries should be kept up-to-date, applying patches to address publicly known vulnerabilities in a timely fashion. **Recommendation**: Third-party libraries should be kept up-to-date, applying patches to address publicly known vulnerabilities in a timely fashion.
Monitoring and logging capabilities should also be in place to detect and respond to potential attacks. Monitoring and logging capabilities should also be in place to detect and respond to potential attacks.
SLSA compliance may also be considered for further supply chain security hardening. SLSA compliance may also be considered for further supply chain security hardening.
## Trust boundary: mirror payloads vs. mirror metadata
`nvm` fetches two very different kinds of data from a Node.js/io.js mirror (`nodejs.org`/`iojs.org` by default, or whatever `$NVM_NODEJS_ORG_MIRROR` and `$NVM_IOJS_ORG_MIRROR` point at), and they sit on opposite sides of a trust boundary:
- **Payloads** — the Node.js/io.js binaries and source tarballs that `nvm install` downloads, unpacks, compiles (for source installs), and runs.
- **Metadata** — everything `nvm` parses *about* those payloads rather than executing: the `index.tab` version list (including each release's LTS codename), and the `SHASUMS`/`SHASUMS256` checksum files.
Conflating the two leads to mis-scoped reports, so the project draws the line explicitly.
### Payloads are trusted, by construction
The entire purpose of `nvm` is to download a mirror's build of Node.js and run it.
A mirror that serves a backdoored binary has arbitrary code execution the moment you `nvm install` and invoke `node`, and no validation inside `nvm` can prevent that - you have chosen to execute that code.
Installing from source (`nvm install -s`) is if anything more direct: the mirror-supplied source tarball is unpacked and its `configure`/`make` build runs arbitrary code on your machine *at install time*, before `node` is ever invoked.
Checksum verification protects **integrity** (a corrupted or truncated download, or a network intermediary that cannot also forge the same-origin `SHASUMS`), not **authenticity** against the mirror itself, since the checksums come from the same origin as the payload.
Selecting a mirror is therefore equivalent to selecting whom you trust for arbitrary code execution in your account.
A malicious payload from the configured mirror is consequently **out of scope**: no privilege boundary is crossed, so there is no privilege to escalate.
### Metadata is not trusted
Parsing a version list is a pure data operation.
A user who runs `nvm ls-remote` to browse available versions - and installs nothing - has not opted into running any code from the mirror.
Metadata can also be attacker-controlled with no mirror misconfiguration at all, via a compromised mirror/CDN or a man-in-the-middle of the channel (see *Threat ID 3*), so it is treated as hostile input.
The invariant `nvm` maintains is:
> Mirror-supplied metadata must never reach a shell/command evaluator, an `awk`/`sed` program body, or an unvalidated filesystem path (see *Threat ID 2*).
This is why version strings from `index.tab` are passed to the downloader as literal `argv` elements rather than re-parsed by the shell ([CVE-2026-10796](https://github.com/advisories/GHSA-3c52-35h2-gfmm), [CVE-2026-1665](https://github.com/advisories/GHSA-4fc5-r4vr-8rp7)); why checksum comparisons pass the mirror's values as `awk -v` **data** and never as program text; and why LTS codenames are constrained to safe alias filenames before naming a file under `$NVM_DIR/alias/lts`, so a hostile codename such as `../../../.bashrc` cannot traverse out of the alias directory.
The point is not that metadata is "more dangerous" than a payload — a trusted payload can obviously do anything.
It is that metadata carries **no** implied grant of code execution, so any code-execution or arbitrary-write primitive reachable purely by parsing it is a defect worth removing on its own merits, independent of how much the payload channel is trusted.
+19 -1
View File
@@ -71,11 +71,29 @@ jobs:
- name: check tests filenames - name: check tests filenames
run: ./rename_test.sh --check run: ./rename_test.sh --check
check_exec:
runs-on: ubuntu-latest
steps:
- uses: step-security/harden-runner@v2
with:
allowed-endpoints:
github.com:443
raw.githubusercontent.com:443
nodejs.org:443
registry.npmjs.org:443
- uses: actions/checkout@v6
- uses: ljharb/actions/node/install@main
name: 'nvm install lts/* && npm install'
with:
node-version: 'lts/*'
- name: check that test files are executable
run: npm run test:check-exec
all: all:
permissions: permissions:
contents: none contents: none
name: 'all linting' name: 'all linting'
needs: [eclint, dockerfile_lint, doctoc, test_naming] needs: [eclint, dockerfile_lint, doctoc, test_naming, check_exec]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: true - run: true
+9 -5
View File
@@ -7,7 +7,7 @@ on:
workflow_dispatch: workflow_dispatch:
inputs: inputs:
version: version:
description: 'nvm version tag (e.g., v0.40.4). Defaults to latest release.' description: 'nvm version tag (e.g., v0.40.4). Defaults to the latest version tag.'
required: false required: false
default: '' default: ''
@@ -18,7 +18,7 @@ jobs:
update-nodejs-org: update-nodejs-org:
if: github.repository == 'nvm-sh/nvm' && github.actor == 'ljharb' if: github.repository == 'nvm-sh/nvm' && github.actor == 'ljharb'
permissions: permissions:
contents: none contents: read # for the "Extract and validate version" step's `gh api .../tags` call via the default github.token
name: 'Create PR to nodejs/nodejs.org' name: 'Create PR to nodejs/nodejs.org'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -41,7 +41,8 @@ jobs:
elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then elif [ "${GITHUB_REF_TYPE}" = "tag" ]; then
TAG="${GITHUB_REF#refs/tags/}" TAG="${GITHUB_REF#refs/tags/}"
else else
TAG="$(gh api "repos/${GITHUB_REPOSITORY}/releases/latest" --jq '.tag_name')" TAG="$(gh api --paginate "repos/${GITHUB_REPOSITORY}/tags" --jq '.[].name' \
| grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V | tail -n 1)"
fi fi
if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then if ! printf '%s\n' "${TAG}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+$'; then
@@ -65,16 +66,19 @@ jobs:
FORK_OWNER="$(gh api user --jq '.login')" FORK_OWNER="$(gh api user --jq '.login')"
DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')" DEFAULT_BRANCH="$(gh api repos/nodejs/nodejs.org --jq '.default_branch')"
gh repo sync "${FORK_OWNER}/nodejs.org" --branch "${DEFAULT_BRANCH}" || true
UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')" UPSTREAM_SHA="$(gh api "repos/nodejs/nodejs.org/git/ref/heads/${DEFAULT_BRANCH}" --jq '.object.sha')"
# Create or reset branch on fork to upstream HEAD # Create or reset branch on fork to upstream HEAD
if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \ if ! gh api "repos/${FORK_OWNER}/nodejs.org/git/refs" \
-f "ref=refs/heads/${BRANCH}" \ -f "ref=refs/heads/${BRANCH}" \
-f "sha=${UPSTREAM_SHA}" > /dev/null 2>&1; then -f "sha=${UPSTREAM_SHA}" > /dev/null; then
gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \ gh api "repos/${FORK_OWNER}/nodejs.org/git/refs/heads/${BRANCH}" \
-X PATCH \ -X PATCH \
-f "sha=${UPSTREAM_SHA}" \ -f "sha=${UPSTREAM_SHA}" \
-f "force=true" > /dev/null -F "force=true" > /dev/null
fi fi
printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}" printf 'fork_owner=%s\n' "${FORK_OWNER}" >> "${GITHUB_OUTPUT}"
+23 -1
View File
@@ -49,7 +49,6 @@ jobs:
contents: read contents: read
needs: [matrix] needs: [matrix]
runs-on: ubuntu-latest runs-on: ubuntu-latest
continue-on-error: ${{ matrix.ref == 'v0.40.0' }} # https://github.com/nvm-sh/nvm/issues/3405
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@@ -81,12 +80,19 @@ jobs:
set -e set -e
export NVM_INSTALL_VERSION="${ref}" export NVM_INSTALL_VERSION="${ref}"
curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash curl -o- "https://raw.githubusercontent.com/nvm-sh/nvm/${ref}/install.sh" | bash
# v0.40.0 with an .nvmrc present is expected to fail (https://github.com/nvm-sh/nvm/issues/3405):
# the steps below tolerate failure for that combination, and the final step
# turns the job red only if the expected failure did NOT happen.
- name: nvm --version - name: nvm --version
id: nvm-version
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
run: | run: |
set +e set +e
. $NVM_DIR/nvm.sh && nvm --version . $NVM_DIR/nvm.sh && nvm --version
- name: nvm install in 1 shell level, ${{ matrix.has-nvmrc }} - name: nvm install in 1 shell level, ${{ matrix.has-nvmrc }}
id: install-1
if: ${{ matrix.shell-level == '1 shlvl' }} if: ${{ matrix.shell-level == '1 shlvl' }}
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
run: | run: |
set -ex set -ex
. $NVM_DIR/nvm.sh . $NVM_DIR/nvm.sh
@@ -96,13 +102,29 @@ jobs:
nvm install nvm install
fi fi
- name: nvm install in 2 shell levels, ${{ matrix.has-nvmrc }} - name: nvm install in 2 shell levels, ${{ matrix.has-nvmrc }}
id: install-2
if: ${{ matrix.shell-level == '2 shlvls' }} if: ${{ matrix.shell-level == '2 shlvls' }}
continue-on-error: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
run: | run: |
if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then if [ '${{ matrix.has-nvmrc }}' == 'nvmrc' ]; then
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version && nvm install" bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version && nvm install"
else else
bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version" bash -c "set -ex && . $NVM_DIR/nvm.sh && echo nvm.sh sourced && nvm --version"
fi fi
- name: 'confirm the expected failure happened (v0.40.0 + nvmrc)'
if: ${{ matrix.ref == 'v0.40.0' && matrix.has-nvmrc == 'nvmrc' }}
env:
SOURCE_OUTCOME: ${{ steps.nvm-version.outcome }}
INSTALL_1_OUTCOME: ${{ steps.install-1.outcome }}
INSTALL_2_OUTCOME: ${{ steps.install-2.outcome }}
run: |
echo "nvm --version: ${SOURCE_OUTCOME}; install (1 shlvl): ${INSTALL_1_OUTCOME}; install (2 shlvls): ${INSTALL_2_OUTCOME}"
if [ "${SOURCE_OUTCOME}" = 'failure' ] || [ "${INSTALL_1_OUTCOME}" = 'failure' ] || [ "${INSTALL_2_OUTCOME}" = 'failure' ]; then
echo 'v0.40.0 failed as expected: https://github.com/nvm-sh/nvm/issues/3405'
else
echo '::error::v0.40.0 with an .nvmrc was expected to fail (https://github.com/nvm-sh/nvm/issues/3405), but every step succeeded. If v0.40.0 somehow works now, remove the expected-failure handling from this workflow.'
exit 1
fi
finisher: finisher:
permissions: permissions:
+6 -10
View File
@@ -2,16 +2,12 @@ name: Automatic Rebase
on: [pull_request_target] on: [pull_request_target]
permissions: read-all permissions:
contents: write # for ljharb/rebase to push code to rebase
pull-requests: read # for ljharb/rebase to get info about PR
jobs: jobs:
_: _:
name: "Automatic Rebase" uses: ljharb/actions/.github/workflows/rebase.yml@main
secrets:
runs-on: ubuntu-latest token: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v6
- uses: ljharb/rebase@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+5 -1
View File
@@ -2,10 +2,14 @@ name: Require “Allow Edits”
on: [pull_request_target] on: [pull_request_target]
permissions: read-all permissions:
contents: read
jobs: jobs:
_: _:
permissions:
pull-requests: read # for ljharb/require-allow-edits to check 'allow edits' on PR
name: "Require “Allow Edits”" name: "Require “Allow Edits”"
runs-on: ubuntu-latest runs-on: ubuntu-latest
+193
View File
@@ -0,0 +1,193 @@
name: 'Tests: alpine'
on: [push, pull_request]
permissions:
contents: read
jobs:
fast:
permissions:
contents: read
# Native runners per arch (no QEMU): arm64 uses the ubuntu-24.04-arm image.
name: 'fast ${{ matrix.arch }} (alpine ${{ matrix.alpine }}, ${{ matrix.shell }})'
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
strategy:
fail-fast: false
matrix:
alpine:
- '3.15'
- '3.19'
- '3'
arch:
- x64
- arm64
shell:
- sh
- bash
- dash
- zsh
# - ksh (#574)
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2
with:
allowed-endpoints:
github.com:443
registry.npmjs.org:443
raw.githubusercontent.com:443
nodejs.org:443
iojs.org:443
unofficial-builds.nodejs.org:443
dl-cdn.alpinelinux.org:443
dl-cdn.alpinelinux.org:80
registry-1.docker.io:443
auth.docker.io:443
production.cloudflare.docker.com:443
production.cloudfront.docker.com:443
- uses: actions/checkout@v6
id: checkout
continue-on-error: true
with:
submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- uses: ljharb/actions/node/install@main
name: 'npm install (on host; node_modules is mounted into the container)'
with:
node-version: 'lts/*'
skip-ls-check: true
- run: npm ls urchin
- name: 'Run fast tests on Alpine ${{ matrix.alpine }} (${{ matrix.arch }})'
run: |
for i in 1 2 3 4 5; do
docker pull alpine:${{ matrix.alpine }} && break
echo "docker pull failed, attempt $i/5"; sleep $((i * 5))
done
docker run --rm \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
-e "TEST_SHELL=${{ matrix.shell }}" \
-e "TERM=xterm-256color" \
-e "GITHUB_ACTIONS=true" \
alpine:${{ matrix.alpine }} \
sh -c '
set -ex
cat /etc/alpine-release; uname -m
for i in 1 2 3 4 5; do
apk add --no-cache \
make bash zsh dash \
grep sed gawk coreutils util-linux findutils ncurses \
curl wget ca-certificates openssl tar xz gzip git \
sudo su-exec libstdc++ libgcc && break
echo "apk add failed, attempt $i/5"; sleep $((i * 5))
done
# Mirror the ubuntu runner: run the suite as a non-root user with
# passwordless sudo and a PTY so the permission/terminal tests
# behave the same. The user takes the mounted checkout uid so
# files stay host-owned (no chown; post-checkout cleanup works).
# No node is installed, so no active version skews the output.
HOST_UID="$(stat -c %u /workspace)"
adduser -D -u "$HOST_UID" tester 2>/dev/null || adduser -D tester
echo "tester ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/tester
chmod 0440 /etc/sudoers.d/tester
export NVM_DIR=/workspace HOME=/home/tester
unset NVM_BIN NVM_INC NVM_CD_FLAGS
su-exec tester script -q -e -c "make TEST_SUITE=fast SHELL=$TEST_SHELL URCHIN=/workspace/node_modules/.bin/urchin test-$TEST_SHELL" /dev/null
'
musl-binary:
permissions:
contents: read
# Regression lock, same-era diagonal only: modern musl node needs a newer
# libstdc++ than old Alpine ships, and arm64-musl exists only from
# v20.20.1/v22.21.1/v24.9.0 (built on modern Alpine), so arm64 pins modern Alpine.
name: 'musl-binary ${{ matrix.arch }} (alpine ${{ matrix.alpine }}, node ${{ matrix.node }})'
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
strategy:
fail-fast: false
matrix:
include:
- { arch: x64, alpine: '3.10', node: v8.17.0 }
- { arch: x64, alpine: '3.10', node: v10.24.1 }
- { arch: x64, alpine: '3.12', node: v12.22.12 }
- { arch: x64, alpine: '3.15', node: v14.21.3 }
- { arch: x64, alpine: '3.16', node: v16.20.2 }
- { arch: x64, alpine: '3.18', node: v18.20.4 }
- { arch: x64, alpine: '3.20', node: v20.18.1 }
- { arch: x64, alpine: '3', node: v22.12.0 }
- { arch: arm64, alpine: '3.20', node: v20.20.1 }
- { arch: arm64, alpine: '3', node: v22.21.1 }
- { arch: arm64, alpine: '3', node: v24.9.0 }
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2
with:
allowed-endpoints:
github.com:443
registry.npmjs.org:443
unofficial-builds.nodejs.org:443
dl-cdn.alpinelinux.org:443
dl-cdn.alpinelinux.org:80
registry-1.docker.io:443
auth.docker.io:443
production.cloudflare.docker.com:443
production.cloudfront.docker.com:443
- uses: actions/checkout@v6
with:
submodules: false
- name: 'Install node ${{ matrix.node }} from a musl binary on Alpine ${{ matrix.alpine }}'
run: |
for i in 1 2 3 4 5; do
docker pull alpine:${{ matrix.alpine }} && break
echo "docker pull failed, attempt $i/5"; sleep $((i * 5))
done
docker run --rm \
-v "${{ github.workspace }}:/workspace" \
-w /workspace \
-e "NODE_VERSION=${{ matrix.node }}" \
-e "TERM=xterm-256color" \
alpine:${{ matrix.alpine }} \
sh -c '
set -ex
cat /etc/alpine-release; uname -m
# libstdc++/libgcc are load-bearing: the unofficial musl node
# binary dynamically links them. No build toolchain: -b forbids
# the source fallback, so a missing binary is a hard failure.
for i in 1 2 3 4 5; do
apk add --no-cache \
bash ca-certificates curl wget tar xz gzip \
grep sed coreutils libstdc++ libgcc && break
echo "apk add failed, attempt $i/5"; sleep $((i * 5))
done
export NVM_DIR=/workspace
unset NVM_BIN NVM_INC NVM_CD_FLAGS
# The default nodejs.org mirror serves no -musl artifacts; this one does.
export NVM_NODEJS_ORG_MIRROR=https://unofficial-builds.nodejs.org/download/release
. /workspace/nvm.sh --no-use
nvm install -b --skip-default-packages "$NODE_VERSION"
nvm use "$NODE_VERSION"
[ "$(node -v)" = "$NODE_VERSION" ] || { echo "version mismatch: $(node -v)"; exit 1; }
node -e "process.exit(0)"
ldd "$(command -v node)" | grep -qi musl
'
all:
permissions:
contents: none
name: 'all alpine tests'
needs: [fast, musl-binary]
runs-on: ubuntu-latest
steps:
- run: true
+9
View File
@@ -47,8 +47,17 @@ jobs:
production.cloudflare.docker.com:443 production.cloudflare.docker.com:443
production.cloudfront.docker.com:443 production.cloudfront.docker.com:443
- uses: actions/checkout@v6 - uses: actions/checkout@v6
id: checkout
continue-on-error: true
with: with:
submodules: true submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- name: Install zsh, additional shells, and awk variant - name: Install zsh, additional shells, and awk variant
run: | run: |
sudo apt-get update sudo apt-get update
+44 -1
View File
@@ -39,8 +39,17 @@ jobs:
azure.archive.ubuntu.com:80 azure.archive.ubuntu.com:80
packages.microsoft.com:443 packages.microsoft.com:443
- uses: actions/checkout@v6 - uses: actions/checkout@v6
id: checkout
continue-on-error: true
with: with:
submodules: true submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- name: Install zsh and additional shells - name: Install zsh and additional shells
run: | run: |
sudo apt-get update sudo apt-get update
@@ -89,11 +98,45 @@ jobs:
run: sudo apt-get install curl -y run: sudo apt-get install curl -y
shell: bash shell: bash
installation_iojs_source_compile:
permissions:
contents: read
name: 'actually compile io.js from source (gcc 4.9 container)'
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- name: Harden Runner
uses: step-security/harden-runner@v2
with:
allowed-endpoints:
github.com:443
mirror.gcr.io:443
storage.googleapis.com:443
iojs.org:443
- uses: actions/checkout@v6
# io.js requires python 2 and gcc <= 5 to compile; the gcc:4.9 image
# (debian jessie) has both, plus curl/wget/xz and CA certificates that
# still validate iojs.org - so the source-install tests run unmodified,
# resolving, downloading, checksumming, and compiling for real.
# The image is pulled through Google's Docker Hub mirror: it serves
# manifests and blobs from a single stable hostname (Docker Hub's blob
# CDN hostnames rotate, which the blocked-egress policy can not allow),
# and it is not subject to Docker Hub's anonymous pull rate limits.
- name: compile io.js from source, for real
run: |
docker run --rm -v "${PWD}:/nvm-under-test" -e NVM_DIR=/nvm-under-test mirror.gcr.io/library/gcc:4.9 bash -ec '
cd "${NVM_DIR}/test/installation_iojs"
sh "./install from source"
sh "./install version specified in .nvmrc from source"
'
all: all:
permissions: permissions:
contents: none contents: none
name: 'all installation_iojs tests' name: 'all installation_iojs tests'
needs: [installation_iojs_without_curl] needs: [installation_iojs_without_curl, installation_iojs_source_compile]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: true - run: true
@@ -45,8 +45,17 @@ jobs:
registry-1.docker.io:443 registry-1.docker.io:443
auth.docker.io:443 auth.docker.io:443
- uses: actions/checkout@v6 - uses: actions/checkout@v6
id: checkout
continue-on-error: true
with: with:
submodules: true submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- uses: ljharb/actions/node/install@main - uses: ljharb/actions/node/install@main
name: 'npm install && version checks' name: 'npm install && version checks'
with: with:
+9
View File
@@ -42,8 +42,17 @@ jobs:
registry-1.docker.io:443 registry-1.docker.io:443
auth.docker.io:443 auth.docker.io:443
- uses: actions/checkout@v6 - uses: actions/checkout@v6
id: checkout
continue-on-error: true
with: with:
submodules: true submodules: true
- name: 'nvmrc submodule fallback (forks without their own nvmrc)'
if: steps.checkout.outcome == 'failure'
shell: bash
run: |
git submodule set-url test/fixtures/nvmrc https://github.com/nvm-sh/nvmrc.git
git submodule sync --recursive
git submodule update --init --recursive
- uses: ljharb/actions/node/install@main - uses: ljharb/actions/node/install@main
name: 'npm install && version checks' name: 'npm install && version checks'
with: with:
+1 -1
View File
@@ -8,7 +8,7 @@ permissions:
jobs: jobs:
tests: tests:
permissions: permissions:
contents: write contents: read # for actions/checkout@v6
name: "tests" name: "tests"
runs-on: ubuntu-latest runs-on: ubuntu-latest
+4
View File
@@ -94,6 +94,8 @@ jobs:
bash.exe "%USERPROFILE%\setup.sh" bash.exe "%USERPROFILE%\setup.sh"
wsl_matrix: wsl_matrix:
permissions:
contents: none
continue-on-error: true continue-on-error: true
name: 'WSL nvm install' name: 'WSL nvm install'
defaults: defaults:
@@ -187,6 +189,8 @@ jobs:
node -v node -v
wsl_matrix_unofficial: wsl_matrix_unofficial:
permissions:
contents: none
continue-on-error: true continue-on-error: true
name: 'WSL nvm install' name: 'WSL nvm install'
defaults: defaults:
+39 -25
View File
@@ -6,7 +6,7 @@
</a> </a>
# Node Version Manager [![Tests](https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml/badge.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.40.5-yellow.svg)][4] [![CII Best Practices](https://bestpractices.dev/projects/684/badge)](https://bestpractices.dev/projects/684) # Node Version Manager [![Tests](https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml/badge.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.40.6-yellow.svg)][4] [![CII Best Practices](https://bestpractices.dev/projects/684/badge)](https://bestpractices.dev/projects/684)
<!-- To update this table of contents, ensure you have run `npm install` then `npm run doctoc` --> <!-- To update this table of contents, ensure you have run `npm install` then `npm run doctoc` -->
<!-- START doctoc generated TOC please keep comment here to allow auto update --> <!-- START doctoc generated TOC please keep comment here to allow auto update -->
@@ -31,6 +31,7 @@
- [Usage](#usage) - [Usage](#usage)
- [Long-term Support](#long-term-support) - [Long-term Support](#long-term-support)
- [Migrating Global Packages While Installing](#migrating-global-packages-while-installing) - [Migrating Global Packages While Installing](#migrating-global-packages-while-installing)
- [Migrating Global Packages Between Installed Versions](#migrating-global-packages-between-installed-versions)
- [Offline Install](#offline-install) - [Offline Install](#offline-install)
- [Default Global Packages From File While Installing](#default-global-packages-from-file-while-installing) - [Default Global Packages From File While Installing](#default-global-packages-from-file-while-installing)
- [io.js](#iojs) - [io.js](#iojs)
@@ -105,10 +106,10 @@ nvm is a version manager for [node.js](https://nodejs.org/en/), designed to be i
To **install** or **update** nvm, you should run the [install script][2]. To do that, you may either download and run the script manually, or use the following cURL or Wget command: To **install** or **update** nvm, you should run the [install script][2]. To do that, you may either download and run the script manually, or use the following cURL or Wget command:
```sh ```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
``` ```
```sh ```sh
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
``` ```
Running either of the above commands downloads a script and runs it. The script clones the nvm repository to `~/.nvm`, and attempts to add the source lines from the snippet below to the correct profile file (`~/.bashrc`, `~/.bash_profile`, `~/.zshrc`, or `~/.profile`). If you find the install script is updating the wrong profile file, set the `$PROFILE` env var to the profile files path, and then rerun the installation script. Running either of the above commands downloads a script and runs it. The script clones the nvm repository to `~/.nvm`, and attempts to add the source lines from the snippet below to the correct profile file (`~/.bashrc`, `~/.bash_profile`, `~/.zshrc`, or `~/.profile`). If you find the install script is updating the wrong profile file, set the `$PROFILE` env var to the profile files path, and then rerun the installation script.
@@ -135,7 +136,7 @@ Eg: `curl ... | NVM_DIR="path/to/nvm"`. Ensure that the `NVM_DIR` does not conta
- The installer can use `git`, `curl`, or `wget` to download `nvm`, whichever is available. - The installer can use `git`, `curl`, or `wget` to download `nvm`, whichever is available.
- You can instruct the installer to not edit your shell config (for example if you already get completions via a [zsh nvm plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/nvm)) by setting `PROFILE=/dev/null` before running the `install.sh` script. Here's an example one-line command to do that: `PROFILE=/dev/null bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash'` - You can instruct the installer to not edit your shell config (for example if you already get completions via a [zsh nvm plugin](https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/nvm)) by setting `PROFILE=/dev/null` before running the `install.sh` script. Here's an example one-line command to do that: `PROFILE=/dev/null bash -c 'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash'`
#### Installing in Docker #### Installing in Docker
@@ -151,7 +152,7 @@ RUN touch "${BASH_ENV}"
RUN echo '. "${BASH_ENV}"' >> ~/.bashrc RUN echo '. "${BASH_ENV}"' >> ~/.bashrc
# Download and install nvm # Download and install nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | PROFILE="${BASH_ENV}" bash RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | PROFILE="${BASH_ENV}" bash
RUN echo node > .nvmrc RUN echo node > .nvmrc
RUN nvm install RUN nvm install
``` ```
@@ -169,7 +170,7 @@ ARG NODE_VERSION=20
RUN apt update && apt install curl -y RUN apt update && apt install curl -y
# install nvm # install nvm
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
# set env # set env
ENV NVM_DIR=/root/.nvm ENV NVM_DIR=/root/.nvm
@@ -195,7 +196,7 @@ After creation of the image you can start container interactively and run comman
docker run --rm -it nvmimage docker run --rm -it nvmimage
root@0a6b5a237c14:/# nvm -v root@0a6b5a237c14:/# nvm -v
0.40.5 0.40.6
root@0a6b5a237c14:/# node -v root@0a6b5a237c14:/# node -v
v19.9.0 v19.9.0
@@ -258,7 +259,7 @@ You can use a task:
```yaml ```yaml
- name: Install nvm - name: Install nvm
ansible.builtin.shell: > ansible.builtin.shell: >
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
args: args:
creates: "{{ ansible_env.HOME }}/.nvm/nvm.sh" creates: "{{ ansible_env.HOME }}/.nvm/nvm.sh"
``` ```
@@ -320,7 +321,7 @@ If you have `git` installed (requires git v1.7.10+):
1. clone this repo in the root of your user profile 1. clone this repo in the root of your user profile
- `cd ~/` from anywhere then `git clone https://github.com/nvm-sh/nvm.git .nvm` - `cd ~/` from anywhere then `git clone https://github.com/nvm-sh/nvm.git .nvm`
1. `cd ~/.nvm` and check out the latest version with `git checkout v0.40.5` 1. `cd ~/.nvm` and check out the latest version with `git checkout v0.40.6`
1. activate `nvm` by sourcing it from your shell: `. ./nvm.sh` 1. activate `nvm` by sourcing it from your shell: `. ./nvm.sh`
Now add these lines to your `~/.bashrc`, `~/.profile`, or `~/.zshrc` file to have it automatically sourced upon login: Now add these lines to your `~/.bashrc`, `~/.profile`, or `~/.zshrc` file to have it automatically sourced upon login:
@@ -429,6 +430,7 @@ In place of a version pointer like "14.7" or "16.3" or "12.22.1", you can use th
- `iojs`: this installs the latest version of [`io.js`](https://iojs.org/en/) - `iojs`: this installs the latest version of [`io.js`](https://iojs.org/en/)
- `stable`: this alias is deprecated, and only truly applies to `node` `v0.12` and earlier. Currently, this is an alias for `node`. - `stable`: this alias is deprecated, and only truly applies to `node` `v0.12` and earlier. Currently, this is an alias for `node`.
- `unstable`: this alias points to `node` `v0.11` - the last "unstable" node release, since post-1.0, all node versions are stable. (in SemVer, versions communicate breakage, not stability). - `unstable`: this alias points to `node` `v0.11` - the last "unstable" node release, since post-1.0, all node versions are stable. (in SemVer, versions communicate breakage, not stability).
- `current`: the version currently active in this shell (i.e. what `node` resolves to via `$PATH`). It is **not** affected by `.nvmrc`. Useful when you want to refer to the active version explicitly &mdash; e.g. `nvm which current` always prints the path to the active `node`, regardless of whether an `.nvmrc` file is present.
### Long-term Support ### Long-term Support
@@ -482,6 +484,17 @@ nvm install-latest-npm
If you've already gotten an error to the effect of "npm does not support Node.js", you'll need to (1) revert to a previous node version (`nvm ls` & `nvm use <your latest _working_ version from the ls>`), (2) delete the newly created node version (`nvm uninstall <your _broken_ version of node from the ls>`), then (3) rerun your `nvm install` with the `--latest-npm` flag. If you've already gotten an error to the effect of "npm does not support Node.js", you'll need to (1) revert to a previous node version (`nvm ls` & `nvm use <your latest _working_ version from the ls>`), (2) delete the newly created node version (`nvm uninstall <your _broken_ version of node from the ls>`), then (3) rerun your `nvm install` with the `--latest-npm` flag.
### Migrating Global Packages Between Installed Versions
`--reinstall-packages-from` is tied to `nvm install`. To migrate global npm packages between versions you _already_ have installed, without (re)installing anything, `nvm use` the destination and run `nvm reinstall-packages` as a standalone command, pointing at the version you want to copy _from_:
```sh
nvm use 22.22.2
nvm reinstall-packages 22.20.0
```
This reinstalls all global packages from `22.20.0` into the currently-active version (`22.22.2`). As with `--reinstall-packages-from`, the npm version itself is not changed.
### Offline Install ### Offline Install
@@ -645,7 +658,7 @@ NVM_AUTH_HEADER="Bearer secret-token" nvm install node
### .nvmrc ### .nvmrc
You can create a `.nvmrc` file containing a node version number (or any other string that `nvm` understands; see `nvm --help` for details) in the project root directory (or any parent directory). You can create a `.nvmrc` file containing a node version number (or any other string that `nvm` understands; see `nvm --help` for details) in the project root directory (or any parent directory).
Afterwards, `nvm use`, `nvm install`, `nvm exec`, `nvm run`, and `nvm which` will use the version specified in the `.nvmrc` file if no version is supplied on the command line. Afterwards, `nvm use`, `nvm install`, and `nvm which` will use the version specified in the `.nvmrc` file if no version is supplied on the command line; if no `.nvmrc` is found either, they exit with status `127`. (`nvm exec` and `nvm run` follow the same `.nvmrc` lookup, but currently fall back to the active node if neither resolves &mdash; treat that fallback as undefined behavior; pass an explicit version if you need predictable scripting.) If you want the currently active version, pass `current` explicitly (e.g. `nvm which current`) &mdash; `current` is not affected by `.nvmrc`.
For example, to make nvm default to the latest 5.9 release, the latest LTS version, or the latest node version for the current directory: For example, to make nvm default to the latest 5.9 release, the latest LTS version, or the latest node version for the current directory:
@@ -945,13 +958,13 @@ If installing nvm on Alpine Linux *is* still what you want or need to do, you sh
### Alpine Linux 3.13+ ### Alpine Linux 3.13+
```sh ```sh
apk add -U curl bash ca-certificates openssl ncurses coreutils python3 make gcc g++ libgcc linux-headers grep util-linux binutils findutils apk add -U curl bash ca-certificates openssl ncurses coreutils python3 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
``` ```
### Alpine Linux 3.5 - 3.12 ### Alpine Linux 3.5 - 3.12
```sh ```sh
apk add -U curl bash ca-certificates openssl ncurses coreutils python2 make gcc g++ libgcc linux-headers grep util-linux binutils findutils apk add -U curl bash ca-certificates openssl ncurses coreutils python2 make gcc g++ libgcc linux-headers grep util-linux binutils findutils
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
``` ```
_Note: Alpine 3.5 can only install NodeJS versions up to v6.9.5, Alpine 3.6 can only install versions up to v6.10.3, Alpine 3.7 installs versions up to v8.9.3, Alpine 3.8 installs versions up to v8.14.0, Alpine 3.9 installs versions up to v10.19.0, Alpine 3.10 installs versions up to v10.24.1, Alpine 3.11 installs versions up to v12.22.6, Alpine 3.12 installs versions up to v12.22.12, Alpine 3.13 & 3.14 install versions up to v14.20.0, Alpine 3.15 & 3.16 install versions up to v16.16.0 (**These are all versions on the main branch**). Alpine 3.5 - 3.12 required the package `python2` to build NodeJS, as they are older versions to build. Alpine 3.13+ requires `python3` to successfully build newer NodeJS versions, but you can use `python2` with Alpine 3.13+ if you need to build versions of node supported in Alpine 3.5 - 3.15, you just need to specify what version of NodeJS you need to install in the package install script._ _Note: Alpine 3.5 can only install NodeJS versions up to v6.9.5, Alpine 3.6 can only install versions up to v6.10.3, Alpine 3.7 installs versions up to v8.9.3, Alpine 3.8 installs versions up to v8.14.0, Alpine 3.9 installs versions up to v10.19.0, Alpine 3.10 installs versions up to v10.24.1, Alpine 3.11 installs versions up to v12.22.6, Alpine 3.12 installs versions up to v12.22.12, Alpine 3.13 & 3.14 install versions up to v14.20.0, Alpine 3.15 & 3.16 install versions up to v16.16.0 (**These are all versions on the main branch**). Alpine 3.5 - 3.12 required the package `python2` to build NodeJS, as they are older versions to build. Alpine 3.13+ requires `python3` to successfully build newer NodeJS versions, but you can use `python2` with Alpine 3.13+ if you need to build versions of node supported in Alpine 3.5 - 3.15, you just need to specify what version of NodeJS you need to install in the package install script._
@@ -985,13 +998,13 @@ export NVM_DIR="$HOME/.nvm"
## Docker For Development Environment ## Docker For Development Environment
To make the development and testing work easier, we have a Dockerfile for development usage, which is based on Ubuntu 18.04 base image, prepared with essential and useful tools for `nvm` development, to build the docker image of the environment, run the docker command at the root of `nvm` repository: To make development and testing work easier we supply a Dockerfile for development usage. It's based on an Ubuntu base image prepared with essential and useful tools for `nvm` development. To build the docker image of the environment, do a Docker build at the root of `nvm` repository:
```sh ```sh
$ docker build -t nvm-dev . $ docker build -t nvm-dev .
``` ```
This will package your current nvm repository with our pre-defined development environment into a docker image named `nvm-dev`, once it's built with success, validate your image via `docker images`: This will package your current nvm working copy with our pre-defined development environment into a Docker image named `nvm-dev`. After the build you should see it appear in the list of images:
```sh ```sh
$ docker images $ docker images
@@ -1000,7 +1013,7 @@ REPOSITORY TAG IMAGE ID CREATED S
nvm-dev latest 9ca4c57a97d8 7 days ago 650 MB nvm-dev latest 9ca4c57a97d8 7 days ago 650 MB
``` ```
If you got no error message, now you can easily involve in: To start and enter a container based on this image:
```sh ```sh
$ docker run -h nvm-dev -it nvm-dev $ docker run -h nvm-dev -it nvm-dev
@@ -1008,12 +1021,9 @@ $ docker run -h nvm-dev -it nvm-dev
nvm@nvm-dev:~/.nvm$ nvm@nvm-dev:~/.nvm$
``` ```
Please note that it'll take about 8 minutes to build the image and the image size would be about 650MB, so it's not suitable for production usage. It takes several minutes to build the image and the image size is about 650MB, so it's not suitable for production usage.
For more information and documentation about docker, please refer to its official website: For more information and documentation about Docker, please refer to its [official website][docker-www] and [documentation][docker-docs]:
- https://www.docker.com/
- https://docs.docker.com/
## Problems ## Problems
@@ -1054,9 +1064,9 @@ You have to make sure that the user directory name in `$HOME` and the user direc
To change the user directory and/or account name follow the instructions [here](https://support.apple.com/en-us/HT201548) To change the user directory and/or account name follow the instructions [here](https://support.apple.com/en-us/HT201548)
[1]: https://github.com/nvm-sh/nvm.git [1]: https://github.com/nvm-sh/nvm.git
[2]: https://github.com/nvm-sh/nvm/blob/v0.40.5/install.sh [2]: https://github.com/nvm-sh/nvm/blob/v0.40.6/install.sh
[3]: https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml [3]: https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml
[4]: https://github.com/nvm-sh/nvm/releases/tag/v0.40.5 [4]: https://github.com/nvm-sh/nvm/releases/tag/v0.40.6
[Urchin]: https://git.sdf.org/tlevine/urchin [Urchin]: https://git.sdf.org/tlevine/urchin
[Fish]: https://fishshell.com [Fish]: https://fishshell.com
@@ -1114,7 +1124,7 @@ Here's what you will need to do:
If one of these broken versions is installed on your system, the above step will likely still succeed even if you didn't include the `--shared-zlib` flag. If one of these broken versions is installed on your system, the above step will likely still succeed even if you didn't include the `--shared-zlib` flag.
However, later, when you attempt to `npm install` something using your old version of node.js, you will see `incorrect data check` errors. However, later, when you attempt to `npm install` something using your old version of node.js, you will see `incorrect data check` errors.
If you want to avoid the possible hassle of dealing with this, include that flag. If you want to avoid the possible hassle of dealing with this, include that flag.
For more details, see [this issue](https://github.com/nodejs/node/issues/39313) and [this comment](https://github.com/nodejs/node/issues/39313#issuecomment-90.40.576) For more details, see [this issue](https://github.com/nodejs/node/issues/39313) and [this comment](https://github.com/nodejs/node/issues/39313#issuecomment-90.40.676)
- Exit back to your native shell. - Exit back to your native shell.
@@ -1141,7 +1151,7 @@ Now you should be able to use node as usual.
If you've encountered this error on WSL-2: If you've encountered this error on WSL-2:
```sh ```sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.6/install.sh | bash
% Total % Received % Xferd Average Speed Time Time Time Current % Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:09 --:--:-- 0curl: (6) Could not resolve host: raw.githubusercontent.com 0 0 0 0 0 0 0 0 --:--:-- 0:00:09 --:--:-- 0curl: (6) Could not resolve host: raw.githubusercontent.com
@@ -1176,7 +1186,7 @@ Currently, the sole maintainer is [@ljharb](https://github.com/ljharb) - more ma
## Project Support ## Project Support
Only the latest version (v0.40.5 at this time) is supported. Only the latest version (v0.40.6 at this time) is supported.
## Enterprise Support ## Enterprise Support
@@ -1192,3 +1202,7 @@ See [LICENSE.md](./LICENSE.md).
Copyright [OpenJS Foundation](https://openjsf.org) and `nvm` contributors. All rights reserved. The [OpenJS Foundation](https://openjsf.org) has registered trademarks and uses trademarks. For a list of trademarks of the [OpenJS Foundation](https://openjsf.org), please see our [Trademark Policy](https://trademark-policy.openjsf.org/) and [Trademark List](https://trademark-list.openjsf.org/). Trademarks and logos not indicated on the [list of OpenJS Foundation trademarks](https://trademark-list.openjsf.org) are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them. Copyright [OpenJS Foundation](https://openjsf.org) and `nvm` contributors. All rights reserved. The [OpenJS Foundation](https://openjsf.org) has registered trademarks and uses trademarks. For a list of trademarks of the [OpenJS Foundation](https://openjsf.org), please see our [Trademark Policy](https://trademark-policy.openjsf.org/) and [Trademark List](https://trademark-list.openjsf.org/). Trademarks and logos not indicated on the [list of OpenJS Foundation trademarks](https://trademark-list.openjsf.org) are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them.
[The OpenJS Foundation](https://openjsf.org/) | [Terms of Use](https://terms-of-use.openjsf.org/) | [Privacy Policy](https://privacy-policy.openjsf.org/) | [Bylaws](https://bylaws.openjsf.org/) | [Code of Conduct](https://code-of-conduct.openjsf.org) | [Trademark Policy](https://trademark-policy.openjsf.org/) | [Trademark List](https://trademark-list.openjsf.org/) | [Cookie Policy](https://www.linuxfoundation.org/cookies/) [The OpenJS Foundation](https://openjsf.org/) | [Terms of Use](https://terms-of-use.openjsf.org/) | [Privacy Policy](https://privacy-policy.openjsf.org/) | [Bylaws](https://bylaws.openjsf.org/) | [Code of Conduct](https://code-of-conduct.openjsf.org) | [Trademark Policy](https://trademark-policy.openjsf.org/) | [Trademark List](https://trademark-list.openjsf.org/) | [Cookie Policy](https://www.linuxfoundation.org/cookies/)
<!-------------------------------------------------------------------->
[docker-docs]: https://docs.docker.com/
[docker-www]: https://www.docker.com/
+20 -8
View File
@@ -6,6 +6,18 @@ nvm_has() {
type "$1" > /dev/null 2>&1 type "$1" > /dev/null 2>&1
} }
# resolves like `command "${1}"` does: only executables on the PATH,
# ignoring shell functions and aliases
nvm_has_executable() {
(
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
# do not abort the subshell when the name is not an alias or a function
unalias "${1-}" 2>/dev/null || true
unset -f "${1-}" 2>/dev/null || true
command -v "${1-}" > /dev/null 2>&1
)
}
nvm_echo() { nvm_echo() {
command printf %s\\n "$*" 2>/dev/null command printf %s\\n "$*" 2>/dev/null
} }
@@ -33,7 +45,7 @@ nvm_install_dir() {
} }
nvm_latest_version() { nvm_latest_version() {
nvm_echo "v0.40.5" nvm_echo "v0.40.6"
} }
nvm_profile_is_bash_or_zsh() { nvm_profile_is_bash_or_zsh() {
@@ -105,9 +117,9 @@ nvm_node_version() {
} }
nvm_download() { nvm_download() {
if nvm_has "curl"; then if nvm_has_executable "curl"; then
curl --fail --compressed -q "$@" command curl --fail --compressed -q "$@"
elif nvm_has "wget"; then elif nvm_has_executable "wget"; then
# Emulate curl with wget # Emulate curl with wget
ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \ ARGS=$(nvm_echo "$@" | command sed -e 's/--progress-bar /--progress=bar /' \
-e 's/--compressed //' \ -e 's/--compressed //' \
@@ -119,7 +131,7 @@ nvm_download() {
-e 's/-o /-O /' \ -e 's/-o /-O /' \
-e 's/-C - /-c /') -e 's/-C - /-c /')
# shellcheck disable=SC2086 # shellcheck disable=SC2086
eval wget $ARGS eval command wget $ARGS
fi fi
} }
@@ -401,7 +413,7 @@ nvm_do_install() {
# Autodetect install method # Autodetect install method
if nvm_has git; then if nvm_has git; then
install_nvm_from_git install_nvm_from_git
elif nvm_has curl || nvm_has wget; then elif nvm_has_executable curl || nvm_has_executable wget; then
install_nvm_as_script install_nvm_as_script
else else
nvm_echo >&2 'You need git, curl, or wget to install nvm' nvm_echo >&2 'You need git, curl, or wget to install nvm'
@@ -414,7 +426,7 @@ nvm_do_install() {
fi fi
install_nvm_from_git install_nvm_from_git
elif [ "${METHOD}" = 'script' ]; then elif [ "${METHOD}" = 'script' ]; then
if ! nvm_has curl && ! nvm_has wget; then if ! nvm_has_executable curl && ! nvm_has_executable wget; then
nvm_echo >&2 "You need curl or wget to install nvm" nvm_echo >&2 "You need curl or wget to install nvm"
exit 1 exit 1
fi fi
@@ -496,7 +508,7 @@ nvm_do_install() {
# during the execution of the install script # during the execution of the install script
# #
nvm_reset() { nvm_reset() {
unset -f nvm_has nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \ unset -f nvm_has nvm_has_executable nvm_install_dir nvm_latest_version nvm_profile_is_bash_or_zsh \
nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \ nvm_source nvm_node_version nvm_download install_nvm_from_git nvm_install_node \
install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \ install_nvm_as_script nvm_try_profile nvm_detect_profile nvm_check_global_modules \
nvm_do_install nvm_reset nvm_default_install_dir nvm_grep nvm_do_install nvm_reset nvm_default_install_dir nvm_grep
+183 -69
View File
@@ -11,7 +11,7 @@
{ # this ensures the entire script is downloaded # { # this ensures the entire script is downloaded #
# shellcheck disable=SC3028 # shellcheck disable=SC3028
NVM_SCRIPT_SOURCE="$_" NVM_SCRIPT_SOURCE="${_:-}"
nvm_is_zsh() { nvm_is_zsh() {
[ -n "${ZSH_VERSION-}" ] [ -n "${ZSH_VERSION-}" ]
@@ -49,6 +49,18 @@ nvm_has() {
type "${1-}" >/dev/null 2>&1 type "${1-}" >/dev/null 2>&1
} }
# resolves like `command "${1}"` does: only executables on the PATH,
# ignoring shell functions and aliases
nvm_has_executable() {
(
# `|| true` so that shells with errexit-style options (eg, zsh's ERR_RETURN)
# do not abort the subshell when the name is not an alias or a function
unalias "${1-}" 2>/dev/null || true
unset -f "${1-}" 2>/dev/null || true
command -v "${1-}" >/dev/null 2>&1
)
}
nvm_has_non_aliased() { nvm_has_non_aliased() {
nvm_has "${1-}" && ! nvm_is_alias "${1-}" nvm_has "${1-}" && ! nvm_is_alias "${1-}"
} }
@@ -87,7 +99,7 @@ nvm_has_colors() {
} }
nvm_curl_libz_support() { nvm_curl_libz_support() {
curl -V 2>/dev/null | nvm_grep "^Features:" | nvm_grep -q "libz" command curl -V 2>/dev/null | nvm_grep "^Features:" | nvm_grep -q "libz"
} }
nvm_curl_use_compression() { nvm_curl_use_compression() {
@@ -97,13 +109,13 @@ nvm_curl_use_compression() {
nvm_get_latest() { nvm_get_latest() {
local NVM_LATEST_URL local NVM_LATEST_URL
local CURL_COMPRESSED_FLAG local CURL_COMPRESSED_FLAG
if nvm_has "curl"; then if nvm_has_executable "curl"; then
if nvm_curl_use_compression; then if nvm_curl_use_compression; then
CURL_COMPRESSED_FLAG="--compressed" CURL_COMPRESSED_FLAG="--compressed"
fi fi
NVM_LATEST_URL="$(curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)" NVM_LATEST_URL="$(command curl ${CURL_COMPRESSED_FLAG:-} -q -w "%{url_effective}\\n" -L -s -S https://latest.nvm.sh -o /dev/null)"
elif nvm_has "wget"; then elif nvm_has_executable "wget"; then
NVM_LATEST_URL="$(wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')" NVM_LATEST_URL="$(command wget -q https://latest.nvm.sh --server-response -O /dev/null 2>&1 | command awk '/^ Location: /{DEST=$2} END{ print DEST }')"
else else
nvm_err 'nvm needs curl or wget to proceed.' nvm_err 'nvm needs curl or wget to proceed.'
return 1 return 1
@@ -127,13 +139,13 @@ nvm_download() {
local NVM_DOWNLOADER local NVM_DOWNLOADER
NVM_DOWNLOADER='' NVM_DOWNLOADER=''
if nvm_has "curl"; then if nvm_has_executable "curl"; then
NVM_DOWNLOADER='curl' NVM_DOWNLOADER='curl'
set -- -q --fail "$@" set -- -q --fail "$@"
if nvm_curl_use_compression; then if nvm_curl_use_compression; then
set -- --compressed "$@" set -- --compressed "$@"
fi fi
elif nvm_has "wget"; then elif nvm_has_executable "wget"; then
NVM_DOWNLOADER='wget' NVM_DOWNLOADER='wget'
# Emulate curl with wget # Emulate curl with wget
local NVM_DOWNLOAD_WGET_COUNT local NVM_DOWNLOAD_WGET_COUNT
@@ -170,12 +182,17 @@ nvm_download() {
set -- "$@" --header "Authorization: ${sanitized_header}" set -- "$@" --header "Authorization: ${sanitized_header}"
fi fi
"${NVM_DOWNLOADER}" "$@" command "${NVM_DOWNLOADER}" "$@"
} }
nvm_sanitize_auth_header() { nvm_sanitize_auth_header() {
# Remove potentially dangerous characters # Remove potentially dangerous characters; allow the full base64 (A-Za-z0-9+/=)
nvm_echo "$1" | command sed 's/[^a-zA-Z0-9:;_. -]//g' # and base64url (A-Za-z0-9-_=) charsets, plus the space, colon, dot, and
# underscore the previous allowlist already permitted, so that values like
# `Basic <base64>` and `Bearer <token>` survive intact.
# token68's '~' is still stripped.
# Note: '-' must be at the end of the bracket expression to be treated as a literal.
nvm_echo "$1" | command sed 's/[^a-zA-Z0-9 :_.+/=-]//g'
} }
nvm_has_system_node() { nvm_has_system_node() {
@@ -548,12 +565,12 @@ ${1}"
$(nvm_wrap_with_color_code 'y' "${warn_text}")" $(nvm_wrap_with_color_code 'y' "${warn_text}")"
} }
nvm_process_nvmrc() { nvm_process_nvmrc_content() {
local NVMRC_PATH local NVMRC_CONTENT
NVMRC_PATH="$1" NVMRC_CONTENT="${1-}"
local lines local lines
lines=$(command sed 's/#.*//' "$NVMRC_PATH" | command sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | nvm_grep -v '^$') lines=$(nvm_echo "${NVMRC_CONTENT}" | command sed 's/#.*//' | command sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | nvm_grep -v '^$')
if [ -z "$lines" ]; then if [ -z "$lines" ]; then
nvm_nvmrc_invalid_msg "${lines}" nvm_nvmrc_invalid_msg "${lines}"
@@ -617,12 +634,19 @@ EOF
nvm_echo "${unpaired_line}" nvm_echo "${unpaired_line}"
} }
nvm_process_nvmrc() {
local NVMRC_PATH
NVMRC_PATH="$1"
nvm_process_nvmrc_content "$(command cat "${NVMRC_PATH}")"
}
nvm_rc_version() { nvm_rc_version() {
local NVMRC_PATH local NVMRC_PATH
NVMRC_PATH="$(nvm_find_nvmrc)" NVMRC_PATH="$(nvm_find_nvmrc)"
if [ ! -e "${NVMRC_PATH}" ]; then if [ ! -e "${NVMRC_PATH}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err "No .nvmrc file found" nvm_err "No version provided and no .nvmrc file found"
fi fi
return 1 return 1
fi fi
@@ -649,7 +673,7 @@ nvm_clang_version() {
} }
nvm_curl_version() { nvm_curl_version() {
curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g' command curl -V | command awk '{ if ($1 == "curl") print $2 }' | command sed 's/-.*$//g'
} }
nvm_version_greater() { nvm_version_greater() {
@@ -1259,6 +1283,13 @@ nvm_make_alias() {
nvm_err "an alias target version is required" nvm_err "an alias target version is required"
return 2 return 2
fi fi
# slashes are legal (eg `lts/iron`), but a `..` component would escape the alias dir
case "/${ALIAS}/" in
*/../*)
nvm_err "invalid alias name: ${ALIAS}"
return 3
;;
esac
nvm_echo "${VERSION}" | tee "$(nvm_alias_path)/${ALIAS}" >/dev/null nvm_echo "${VERSION}" | tee "$(nvm_alias_path)/${ALIAS}" >/dev/null
} }
@@ -1343,7 +1374,24 @@ nvm_alias() {
return 2 return 2
fi fi
command sed 's/#.*//; s/[[:space:]]*$//' "${NVM_ALIAS_PATH}" | command awk 'NF' if [ ! -r "${NVM_ALIAS_PATH}" ]; then
# an existing-but-unreadable alias file yields empty output with a success
# status - a nonzero status here would make `nvm_ensure_default_set`
# overwrite an existing default alias it merely could not read
nvm_err "Alias file is not readable: ${NVM_ALIAS_PATH}"
return 0
fi
local NVM_ALIAS_LINE
while IFS= read -r NVM_ALIAS_LINE || [ -n "${NVM_ALIAS_LINE}" ]; do
NVM_ALIAS_LINE="${NVM_ALIAS_LINE%%#*}"
case "${NVM_ALIAS_LINE}" in
*[![:space:]]*) ;;
*) continue ;;
esac
NVM_ALIAS_LINE="${NVM_ALIAS_LINE%"${NVM_ALIAS_LINE##*[![:space:]]}"}"
nvm_echo "${NVM_ALIAS_LINE}"
done < "${NVM_ALIAS_PATH}"
} }
nvm_ls_current() { nvm_ls_current() {
@@ -1376,24 +1424,32 @@ nvm_resolve_alias() {
local ALIAS local ALIAS
ALIAS="${PATTERN}" ALIAS="${PATTERN}"
local ALIAS_TEMP local ALIAS_TEMP
local ALIAS_OUTPUT
local SEEN_ALIASES local SEEN_ALIASES
SEEN_ALIASES="${ALIAS}" SEEN_ALIASES="
local NVM_ALIAS_INDEX ${ALIAS}
NVM_ALIAS_INDEX=1 "
while true; do while true; do
ALIAS_TEMP="$( (nvm_alias "${ALIAS}" 2>/dev/null | command head -n "${NVM_ALIAS_INDEX}" | command tail -n 1) || nvm_echo)" ALIAS_OUTPUT="$(nvm_alias "${ALIAS}" 2>/dev/null)" || ALIAS_OUTPUT=''
ALIAS_TEMP="${ALIAS_OUTPUT%%
*}"
if [ -z "${ALIAS_TEMP}" ]; then if [ -z "${ALIAS_TEMP}" ]; then
break break
fi fi
if command printf '%b' "${SEEN_ALIASES}" | nvm_grep -q -e "^${ALIAS_TEMP}$"; then case "${SEEN_ALIASES}" in
ALIAS="∞" *"
break ${ALIAS_TEMP}
fi "*)
ALIAS="∞"
break
;;
esac
SEEN_ALIASES="${SEEN_ALIASES}\\n${ALIAS_TEMP}" SEEN_ALIASES="${SEEN_ALIASES}${ALIAS_TEMP}
"
ALIAS="${ALIAS_TEMP}" ALIAS="${ALIAS_TEMP}"
done done
@@ -1474,6 +1530,17 @@ nvm_strip_iojs_prefix() {
nvm_ls() { nvm_ls() {
local PATTERN local PATTERN
PATTERN="${1-}" PATTERN="${1-}"
case "${PATTERN}" in
*'#'* | *'
'*)
local NVMRC_PATTERN
if ! NVMRC_PATTERN="$(nvm_process_nvmrc_content "${PATTERN}" 2>/dev/null)"; then
nvm_echo 'N/A'
return 3
fi
PATTERN="${NVMRC_PATTERN}"
;;
esac
local VERSIONS local VERSIONS
VERSIONS='' VERSIONS=''
if [ "${PATTERN}" = 'current' ]; then if [ "${PATTERN}" = 'current' ]; then
@@ -1737,6 +1804,7 @@ nvm_ls_remote_index_tab() {
command mkdir -p "$(nvm_alias_path)/lts" command mkdir -p "$(nvm_alias_path)/lts"
{ command awk '{ { command awk '{
if ($10 ~ /^\-?$/) { next } if ($10 ~ /^\-?$/) { next }
if (tolower($10) !~ /^[a-z0-9][a-z0-9._-]*$/) { next }
if ($10 && !a[tolower($10)]++) { if ($10 && !a[tolower($10)]++) {
if (alias) { print alias, version } if (alias) { print alias, version }
alias_name = "lts/" tolower($10) alias_name = "lts/" tolower($10)
@@ -2171,6 +2239,7 @@ nvm_get_arch() {
x86_64 | amd64) NVM_ARCH="x64" ;; x86_64 | amd64) NVM_ARCH="x64" ;;
i*86) NVM_ARCH="x86" ;; i*86) NVM_ARCH="x86" ;;
aarch64 | armv8l) NVM_ARCH="arm64" ;; aarch64 | armv8l) NVM_ARCH="arm64" ;;
loongarch64) NVM_ARCH="loong64" ;;
*) NVM_ARCH="${HOST_ARCH}" ;; *) NVM_ARCH="${HOST_ARCH}" ;;
esac esac
@@ -2190,10 +2259,12 @@ nvm_get_arch() {
HOST_ARCH=armv7l HOST_ARCH=armv7l
fi fi
if [ -f "/etc/alpine-release" ]; then if [ -f "/etc/alpine-release" ] && [ "_${NVM_OS}" = "_linux" ]; then
# Alpine Linux uses musl libc; only x64-musl binaries are available # Alpine Linux uses musl libc; map to musl variants where available
# See https://unofficial-builds.nodejs.org/download/release/
case "${NVM_ARCH}" in case "${NVM_ARCH}" in
x64) NVM_ARCH=x64-musl ;; x64) NVM_ARCH=x64-musl ;;
arm64) NVM_ARCH=arm64-musl ;;
esac esac
fi fi
@@ -2438,15 +2509,10 @@ nvm_get_download_slug() {
fi fi
fi fi
# If running MAC M1 :: Node v14.17.0 was the first version to offer official experimental support: # If running MAC M1 :: ARM64 binaries are not available for Node < 16.0.0
# https://github.com/nodejs/node/issues/40126 (although binary distributions aren't available until v16) # https://github.com/nodejs/node/issues/40126 (binary distributions aren't available until v16)
if \ if nvm_version_greater '16.0.0' "${VERSION}" && [ "_${NVM_OS}" = '_darwin' ] && [ "${NVM_ARCH}" = 'arm64' ]; then
nvm_version_greater '14.17.0' "${VERSION}" \ NVM_ARCH=x64
|| (nvm_version_greater_than_or_equal_to "${VERSION}" '15.0.0' && nvm_version_greater '16.0.0' "${VERSION}") \
; then
if [ "_${NVM_OS}" = '_darwin' ] && [ "${NVM_ARCH}" = 'arm64' ]; then
NVM_ARCH=x64
fi
fi fi
if [ "${KIND}" = 'binary' ]; then if [ "${KIND}" = 'binary' ]; then
@@ -3107,21 +3173,28 @@ nvm_cache_dir() {
nvm_ls_cached() { nvm_ls_cached() {
local PATTERN local PATTERN
PATTERN="${1-}" PATTERN="${1-}"
local CACHE_BIN_DIR local NVM_CACHE_DIR
CACHE_BIN_DIR="$(nvm_cache_dir)/bin" NVM_CACHE_DIR="$(nvm_cache_dir)"
if [ ! -d "${CACHE_BIN_DIR}" ]; then
return
fi
local NVM_OS local NVM_OS
NVM_OS="$(nvm_get_os)" NVM_OS="$(nvm_get_os)"
local NVM_ARCH local NVM_ARCH
NVM_ARCH="$(nvm_get_arch)" NVM_ARCH="$(nvm_get_arch)"
local SUFFIX local SUFFIX
SUFFIX="${NVM_OS}-${NVM_ARCH}" SUFFIX="${NVM_OS}-${NVM_ARCH}"
# shellcheck disable=SC2010 {
command ls -1 "${CACHE_BIN_DIR}" \ if [ -d "${NVM_CACHE_DIR}/bin" ]; then
| nvm_grep "^node-v.*-${SUFFIX}\$" \ # shellcheck disable=SC2010
| command sed "s/^node-\\(v[0-9][0-9.]*\\)-${SUFFIX}\$/\\1/" \ command ls -1 "${NVM_CACHE_DIR}/bin" \
| nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*-${SUFFIX}\$" \
| command sed "s/-${SUFFIX}\$//"
fi
if [ -d "${NVM_CACHE_DIR}/src" ]; then
# shellcheck disable=SC2010
command ls -1 "${NVM_CACHE_DIR}/src" \
| nvm_grep "^\\(node\\|iojs\\)-v[0-9][0-9.]*\$"
fi
} \
| command sed 's/^node-//' \
| nvm_grep "$(nvm_ensure_version_prefix "${PATTERN}")" \ | nvm_grep "$(nvm_ensure_version_prefix "${PATTERN}")" \
| command sort -t. -u -k 1.2,1n -k 2,2n -k 3,3n | command sort -t. -u -k 1.2,1n -k 2,2n -k 3,3n
} }
@@ -3222,7 +3295,7 @@ nvm() {
nvm_echo ' nvm --help Show this message' nvm_echo ' nvm --help Show this message'
nvm_echo ' --no-colors Suppress colored output' nvm_echo ' --no-colors Suppress colored output'
nvm_echo ' nvm --version Print out the installed version of nvm' nvm_echo ' nvm --version Print out the installed version of nvm'
nvm_echo ' nvm install [<version>] Download and install a <version>. Uses .nvmrc if available and version is omitted.' nvm_echo ' nvm install [<version>] Download and install a <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm install`:' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm install`:'
nvm_echo ' -s Skip binary download, install from source only.' nvm_echo ' -s Skip binary download, install from source only.'
nvm_echo ' -b Skip source download, install from binary only.' nvm_echo ' -b Skip source download, install from binary only.'
@@ -3239,23 +3312,23 @@ nvm() {
nvm_echo ' nvm uninstall <version> Uninstall a version' nvm_echo ' nvm uninstall <version> Uninstall a version'
nvm_echo ' nvm uninstall --lts Uninstall using automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' nvm uninstall --lts Uninstall using automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' nvm uninstall --lts=<LTS name> Uninstall using automatic alias for provided LTS line, if available.' nvm_echo ' nvm uninstall --lts=<LTS name> Uninstall using automatic alias for provided LTS line, if available.'
nvm_echo ' nvm use [<version>] Modify PATH to use <version>. Uses .nvmrc if available and version is omitted.' nvm_echo ' nvm use [current | <version>] Modify PATH to use <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm use`:' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm use`:'
nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.' nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' --save Writes the specified version to .nvmrc.' nvm_echo ' --save Writes the specified version to .nvmrc.'
nvm_echo ' nvm exec [<version>] [<command>] Run <command> on <version>. Uses .nvmrc if available and version is omitted.' nvm_echo ' nvm exec [current | <version>] [<command>] Run <command> on <version>. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm exec`:' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm exec`:'
nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.' nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' nvm run [<version>] [<args>] Run `node` on <version> with <args> as arguments. Uses .nvmrc if available and version is omitted.' nvm_echo ' nvm run [current | <version>] [<args>] Run `node` on <version> with <args> as arguments. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm run`:' nvm_echo ' The following optional arguments, if provided, must appear directly after `nvm run`:'
nvm_echo ' --silent Silences stdout/stderr output' nvm_echo ' --silent Silences stdout/stderr output'
nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.' nvm_echo ' --lts Uses automatic LTS (long-term support) alias `lts/*`, if available.'
nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.' nvm_echo ' --lts=<LTS name> Uses automatic alias for provided LTS line, if available.'
nvm_echo ' nvm current Display currently activated version of Node' nvm_echo ' nvm current Display the active node version (resolved via $PATH; not affected by .nvmrc).'
nvm_echo ' nvm ls [<version>] List installed versions, matching a given <version> if provided' nvm_echo ' nvm ls [<version>] List installed versions, matching a given <version> if provided'
nvm_echo ' --no-colors Suppress colored output' nvm_echo ' --no-colors Suppress colored output'
nvm_echo ' --no-alias Suppress `nvm alias` output' nvm_echo ' --no-alias Suppress `nvm alias` output'
@@ -3276,7 +3349,7 @@ nvm() {
nvm_echo ' nvm install-latest-npm Attempt to upgrade to the latest working `npm` on the current node version' nvm_echo ' nvm install-latest-npm Attempt to upgrade to the latest working `npm` on the current node version'
nvm_echo ' nvm reinstall-packages <version> Reinstall global `npm` packages contained in <version> to current version' nvm_echo ' nvm reinstall-packages <version> Reinstall global `npm` packages contained in <version> to current version'
nvm_echo ' nvm unload Unload `nvm` from shell' nvm_echo ' nvm unload Unload `nvm` from shell'
nvm_echo ' nvm which [current | <version>] Display path to installed node version. Uses .nvmrc if available and version is omitted.' nvm_echo ' nvm which [current | <version>] Display path to installed node version. Uses .nvmrc if version is omitted; otherwise errors.'
nvm_echo ' --silent Silences stdout/stderr output when a version is omitted' nvm_echo ' --silent Silences stdout/stderr output when a version is omitted'
nvm_echo ' nvm cache dir Display path to the cache directory for nvm' nvm_echo ' nvm cache dir Display path to the cache directory for nvm'
nvm_echo ' nvm cache clear Empty cache directory for nvm' nvm_echo ' nvm cache clear Empty cache directory for nvm'
@@ -3338,7 +3411,9 @@ nvm() {
fi fi
;; ;;
*) *)
>&2 nvm --help nvm_err 'Usage: nvm cache dir'
nvm_err ' nvm cache clear'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
;; ;;
esac esac
@@ -3572,7 +3647,7 @@ nvm() {
esac esac
done done
if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has "curl" && ! nvm_has "wget"; then if [ "${NVM_OFFLINE}" != 1 ] && ! nvm_has_executable "curl" && ! nvm_has_executable "wget"; then
nvm_err 'nvm needs curl or wget to proceed.' nvm_err 'nvm needs curl or wget to proceed.'
return 1 return 1
fi fi
@@ -3594,7 +3669,9 @@ nvm() {
else else
{ provided_version="$(nvm_rc_version 3>&1 1>&4)"; } 4>&1 { provided_version="$(nvm_rc_version 3>&1 1>&4)"; } 4>&1
if [ $version_not_provided -eq 1 ] && [ -z "${provided_version}" ]; then if [ $version_not_provided -eq 1 ] && [ -z "${provided_version}" ]; then
>&2 nvm --help nvm_err 'Usage: nvm install [<version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
fi fi
@@ -3732,10 +3809,10 @@ nvm() {
nvm install-latest-npm nvm install-latest-npm
EXIT_CODE=$? EXIT_CODE=$?
fi fi
if [ $EXIT_CODE -ne 0 ] && [ -z "${SKIP_DEFAULT_PACKAGES-}" ]; then if [ $EXIT_CODE -eq 0 ] && [ -z "${SKIP_DEFAULT_PACKAGES-}" ]; then
nvm_install_default_packages nvm_install_default_packages
fi fi
if [ $EXIT_CODE -ne 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then if [ $EXIT_CODE -eq 0 ] && [ -n "${REINSTALL_PACKAGES_FROM-}" ] && [ "_${REINSTALL_PACKAGES_FROM}" != "_N/A" ]; then
nvm reinstall-packages "${REINSTALL_PACKAGES_FROM}" nvm reinstall-packages "${REINSTALL_PACKAGES_FROM}"
EXIT_CODE=$? EXIT_CODE=$?
fi fi
@@ -3753,7 +3830,7 @@ nvm() {
EXIT_CODE=$? EXIT_CODE=$?
fi fi
if [ $EXIT_CODE -ne 0 ] && [ -n "${ALIAS-}" ]; then if [ $EXIT_CODE -eq 0 ] && [ -n "${ALIAS-}" ]; then
nvm alias "${ALIAS}" "${provided_version}" nvm alias "${ALIAS}" "${provided_version}"
EXIT_CODE=$? EXIT_CODE=$?
fi fi
@@ -3852,7 +3929,10 @@ nvm() {
;; ;;
"uninstall") "uninstall")
if [ $# -ne 1 ]; then if [ $# -ne 1 ]; then
>&2 nvm --help nvm_err 'Usage: nvm uninstall <version>'
nvm_err ' nvm uninstall --lts'
nvm_err ' nvm uninstall --lts=<LTS name>'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
@@ -4041,7 +4121,9 @@ nvm() {
fi fi
if [ -z "${VERSION}" ]; then if [ -z "${VERSION}" ]; then
>&2 nvm --help nvm_err 'Usage: nvm use [<version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
@@ -4165,7 +4247,9 @@ nvm() {
VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||: VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||:
fi fi
if [ "${VERSION:-N/A}" = 'N/A' ]; then if [ "${VERSION:-N/A}" = 'N/A' ]; then
>&2 nvm --help nvm_err 'Usage: nvm run [<version>] [<args>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
fi fi
@@ -4179,6 +4263,14 @@ nvm() {
if [ $has_checked_nvmrc -ne 1 ]; then if [ $has_checked_nvmrc -ne 1 ]; then
{ NVM_RC_VERSION="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1 { NVM_RC_VERSION="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1
fi fi
if [ -z "${NVM_RC_VERSION-}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err 'WARNING: `nvm run` was invoked without a version argument and without an .nvmrc file.'
nvm_err ' Falling back to the active node version; this will become an error in a future release.'
nvm_err ' Pass `current` explicitly (e.g. `nvm run current ...`) to silence this warning.'
fi
NVM_RC_VERSION="$(nvm_version current)" ||:
fi
provided_version="${NVM_RC_VERSION}" provided_version="${NVM_RC_VERSION}"
IS_VERSION_FROM_NVMRC=1 IS_VERSION_FROM_NVMRC=1
VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||: VERSION="$(nvm_version "${NVM_RC_VERSION}")" ||:
@@ -4236,19 +4328,36 @@ nvm() {
local provided_version local provided_version
provided_version="$1" provided_version="$1"
local VERSION_SOURCE
VERSION_SOURCE=''
if [ "${NVM_LTS-}" != '' ]; then if [ "${NVM_LTS-}" != '' ]; then
provided_version="lts/${NVM_LTS:-*}" provided_version="lts/${NVM_LTS:-*}"
VERSION="${provided_version}" VERSION="${provided_version}"
VERSION_SOURCE='lts'
elif [ -n "${provided_version}" ]; then elif [ -n "${provided_version}" ]; then
VERSION="$(nvm_version "${provided_version}")" ||: VERSION="$(nvm_version "${provided_version}")" ||:
if [ "_${VERSION}" = '_N/A' ] && ! nvm_is_valid_version "${provided_version}"; then if [ "_${VERSION}" = '_N/A' ] && ! nvm_is_valid_version "${provided_version}"; then
{ provided_version="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1 { provided_version="$(NVM_SILENT="${NVM_SILENT:-0}" nvm_rc_version 3>&1 1>&4)"; } 4>&1 && has_checked_nvmrc=1
VERSION="$(nvm_version "${provided_version}")" ||: VERSION="$(nvm_version "${provided_version}")" ||:
if [ -n "${provided_version}" ]; then
VERSION_SOURCE='nvmrc'
fi
else else
VERSION_SOURCE='arg'
shift shift
fi fi
fi fi
if [ -z "${VERSION_SOURCE}" ]; then
if [ "${NVM_SILENT:-0}" -ne 1 ]; then
nvm_err 'WARNING: `nvm exec` was invoked without a version argument and without an .nvmrc file.'
nvm_err ' Falling back to the active node version; this will become an error in a future release.'
nvm_err ' Pass `current` explicitly (e.g. `nvm exec current ...`) to silence this warning.'
fi
provided_version='current'
VERSION="$(nvm_version current)" ||:
fi
nvm_ensure_version_installed "${provided_version}" nvm_ensure_version_installed "${provided_version}"
EXIT_CODE=$? EXIT_CODE=$?
if [ "${EXIT_CODE}" != "0" ]; then if [ "${EXIT_CODE}" != "0" ]; then
@@ -4383,7 +4492,9 @@ nvm() {
VERSION="${provided_version-}" VERSION="${provided_version-}"
fi fi
if [ -z "${VERSION}" ]; then if [ -z "${VERSION}" ]; then
>&2 nvm --help nvm_err 'Usage: nvm which [current | <version>]'
nvm_err ' Provide a <version>, or run from a directory containing an .nvmrc file.'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
@@ -4480,7 +4591,8 @@ nvm() {
NVM_ALIAS_DIR="$(nvm_alias_path)" NVM_ALIAS_DIR="$(nvm_alias_path)"
command mkdir -p "${NVM_ALIAS_DIR}" command mkdir -p "${NVM_ALIAS_DIR}"
if [ $# -ne 1 ]; then if [ $# -ne 1 ]; then
>&2 nvm --help nvm_err 'Usage: nvm unalias <name>'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
if [ "${1#*\/}" != "${1-}" ]; then if [ "${1#*\/}" != "${1-}" ]; then
@@ -4517,7 +4629,8 @@ nvm() {
;; ;;
"install-latest-npm") "install-latest-npm")
if [ $# -ne 0 ]; then if [ $# -ne 0 ]; then
>&2 nvm --help nvm_err 'Usage: nvm install-latest-npm'
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
@@ -4525,7 +4638,8 @@ nvm() {
;; ;;
"reinstall-packages" | "copy-packages") "reinstall-packages" | "copy-packages")
if [ $# -ne 1 ]; then if [ $# -ne 1 ]; then
>&2 nvm --help nvm_err "Usage: nvm ${COMMAND} <version>"
nvm_err ' Run `nvm --help` for full help.'
return 127 return 127
fi fi
@@ -4623,7 +4737,7 @@ nvm() {
NVM_VERSION_ONLY=true NVM_LTS="${NVM_LTS-}" nvm_remote_version "${PATTERN:-node}" NVM_VERSION_ONLY=true NVM_LTS="${NVM_LTS-}" nvm_remote_version "${PATTERN:-node}"
;; ;;
"--version" | "-v") "--version" | "-v")
nvm_echo '0.40.5' nvm_echo '0.40.6'
;; ;;
"unload") "unload")
nvm deactivate >/dev/null 2>&1 nvm deactivate >/dev/null 2>&1
@@ -4652,7 +4766,7 @@ nvm() {
nvm_version_greater nvm_version_greater_than_or_equal_to \ nvm_version_greater nvm_version_greater_than_or_equal_to \
nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \ nvm_print_npm_version nvm_install_latest_npm nvm_npm_global_modules \
nvm_has_system_node nvm_has_system_iojs \ nvm_has_system_node nvm_has_system_iojs \
nvm_download nvm_get_latest nvm_has nvm_install_default_packages nvm_get_default_packages \ nvm_download nvm_get_latest nvm_has nvm_has_executable nvm_install_default_packages nvm_get_default_packages \
nvm_curl_use_compression nvm_curl_version \ nvm_curl_use_compression nvm_curl_version \
nvm_auto nvm_supports_xz \ nvm_auto nvm_supports_xz \
nvm_echo nvm_err nvm_grep nvm_cd \ nvm_echo nvm_err nvm_grep nvm_cd \
@@ -4668,7 +4782,7 @@ nvm() {
nvm_get_colors nvm_set_colors nvm_print_color_code nvm_wrap_with_color_code nvm_format_help_message_colors \ nvm_get_colors nvm_set_colors nvm_print_color_code nvm_wrap_with_color_code nvm_format_help_message_colors \
nvm_echo_with_colors nvm_err_with_colors \ nvm_echo_with_colors nvm_err_with_colors \
nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \ nvm_get_artifact_compression nvm_install_binary_extract nvm_extract_tarball \
nvm_process_nvmrc nvm_nvmrc_invalid_msg \ nvm_process_nvmrc nvm_process_nvmrc_content nvm_nvmrc_invalid_msg \
nvm_write_nvmrc \ nvm_write_nvmrc \
>/dev/null 2>&1 >/dev/null 2>&1
unset NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \ unset NVM_NODEJS_ORG_MIRROR NVM_IOJS_ORG_MIRROR NVM_DIR \
+4 -4
View File
@@ -1,6 +1,6 @@
{ {
"name": "nvm", "name": "nvm",
"version": "0.40.5", "version": "0.40.6",
"description": "Node Version Manager - Simple bash script to manage multiple active node.js versions", "description": "Node Version Manager - Simple bash script to manage multiple active node.js versions",
"directories": { "directories": {
"test": "test" "test": "test"
@@ -14,7 +14,7 @@
"test/installation/node": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=installation_node test-$shell", "test/installation/node": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=installation_node test-$shell",
"test/installation/iojs": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=installation_iojs test-$shell", "test/installation/iojs": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=installation_iojs test-$shell",
"test/sourcing": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=sourcing test-$shell", "test/sourcing": "shell=$(basename -- $(ps -o comm= $(ps -o ppid= -p $PPID)) | sed 's/^-//'); make TEST_SUITE=sourcing test-$shell",
"test:check-exec": "(IFS=$'\\n'; for file in $(git ls-files test); do if [ ! -x \"$file\" ] && [[ \"$file\" != *.* ]] && [[ \"$file\" != test/fixtures/* ]]; then echo \"$file\"; fi; done) | tee /dev/stderr | awk 'END {if (NR > 0) exit 1}'", "test:check-exec": "git -c core.quotePath=false ls-files test | while IFS= read -r file; do if [ ! -x \"$file\" ]; then case \"$file\" in test/fixtures/*|*.json|*.txt|*.sh|*.js|*.log|*.tab|*.gitkeep) ;; *) echo \"$file\" ;; esac; fi; done | tee /dev/stderr | awk 'END {if (NR > 0) exit 1}'",
"test:check-nonexec": "(IFS=$'\\n'; for file in $(git ls-files test); do if [ -x \"$file\" ] && [ ! -d \"$file\" ] && { [[ \"$file\" =~ '\\.(json|txt|sh|js|log)$' ]] || [[ \"$file\" =~ '^test/(mocks|fixtures)/.*' ]]; }; then echo \"$file\"; fi; done) | tee /dev/stderr | awk 'END {if (NR > 0) exit 1}'", "test:check-nonexec": "(IFS=$'\\n'; for file in $(git ls-files test); do if [ -x \"$file\" ] && [ ! -d \"$file\" ] && { [[ \"$file\" =~ '\\.(json|txt|sh|js|log)$' ]] || [[ \"$file\" =~ '^test/(mocks|fixtures)/.*' ]]; }; then echo \"$file\"; fi; done) | tee /dev/stderr | awk 'END {if (NR > 0) exit 1}'",
"doctoc": "doctoc --title='## Table of Contents' --github README.md", "doctoc": "doctoc --title='## Table of Contents' --github README.md",
"predoctoc:check": "cp README.md v-README.md.orig && npm run doctoc", "predoctoc:check": "cp README.md v-README.md.orig && npm run doctoc",
@@ -43,11 +43,11 @@
"homepage": "https://github.com/nvm-sh/nvm", "homepage": "https://github.com/nvm-sh/nvm",
"devDependencies": { "devDependencies": {
"dockerfile_lint": "^0.3.4", "dockerfile_lint": "^0.3.4",
"doctoc": "^2.2.1", "doctoc": "^2.5.0",
"eclint": "^2.8.1", "eclint": "^2.8.1",
"markdown-link-check": "^3.14.2", "markdown-link-check": "^3.14.2",
"replace": "^1.2.2", "replace": "^1.2.2",
"semver": "^7.7.3", "semver": "^7.8.5",
"urchin": "^0.0.5" "urchin": "^0.0.5"
} }
} }
+33
View File
@@ -50,6 +50,39 @@ make_echo() {
chmod a+x "$1" chmod a+x "$1"
} }
# `command curl` bypasses shell functions and aliases, so tests that mock curl
# must provide an actual executable on the PATH: this creates one in the given
# directory. Invoked as `curl -V`, it prints ${VERSION_MESSAGE} (exported here
# on the mock's behalf); any other invocation runs the body given as the
# second argument, or fails.
make_fake_curl() {
local FAKE_BIN_DIR
FAKE_BIN_DIR="${1-}"
[ -n "${FAKE_BIN_DIR}" ] || return 1
local FAKE_CURL_BODY
FAKE_CURL_BODY="${2-}"
if [ -z "${FAKE_CURL_BODY}" ]; then
FAKE_CURL_BODY='echo >&2 "This fake curl only takes one parameter, -V"
exit 1'
fi
mkdir -p "${FAKE_BIN_DIR}" || return 2
{
echo '#!/bin/sh'
echo 'if [ "$#" -eq 1 ] && [ "$1" = "-V" ]; then'
echo ' echo "${VERSION_MESSAGE}"'
echo ' exit 0'
echo 'fi'
printf '%s\n' "${FAKE_CURL_BODY}"
} > "${FAKE_BIN_DIR}/curl"
chmod +x "${FAKE_BIN_DIR}/curl"
# the fake curl reads VERSION_MESSAGE from the environment
export VERSION_MESSAGE
}
make_fake_node() { make_fake_node() {
local VERSION local VERSION
VERSION="${1-}" VERSION="${1-}"
@@ -0,0 +1,17 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file whose name contains spaces
mkdir -p ../../../alias
printf 'v22.1.0\n' > "../../../alias/test edge spaces"
ACTUAL="$(nvm_alias "test edge spaces")"
EXPECTED='v22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
rm -f "../../../alias/test edge spaces"
@@ -0,0 +1,20 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file where the first line has a valid version
# followed by a second line of binary-like data
printf 'v22.1.0\n' > ../../../alias/test-edge-binary
printf '\001\002\003\377\n' >> ../../../alias/test-edge-binary
ACTUAL="$(nvm_alias test-edge-binary)"
# nvm_alias emits every non-blank, non-comment line — first line should be the version
FIRST_LINE="$(nvm_echo "${ACTUAL}" | command head -n 1)"
EXPECTED='v22.1.0'
[ "${FIRST_LINE}" = "${EXPECTED}" ] || die "expected first line >${EXPECTED}<, got >${FIRST_LINE}<"
rm -f ../../../alias/test-edge-binary
+22
View File
@@ -0,0 +1,22 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with Windows-style line endings (CRLF)
printf 'v22.1.0\r\n' > ../../../alias/test-edge-cr
ACTUAL="$(nvm_alias test-edge-cr)"
EXPECTED='v22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
# Create an alias file with bare carriage return (no newline)
printf 'v22.2.0\r' > ../../../alias/test-edge-cr-bare
ACTUAL="$(nvm_alias test-edge-cr-bare)"
EXPECTED='v22.2.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for bare CR, got >${ACTUAL}<"
rm -f ../../../alias/test-edge-cr ../../../alias/test-edge-cr-bare
@@ -0,0 +1,17 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file containing only comments
printf '# this is a comment\n# another comment\n' > ../../../alias/test-edge-comments
ACTUAL="$(nvm_alias test-edge-comments 2>/dev/null)"
EXIT_CODE="$(nvm_alias test-edge-comments 2>/dev/null; echo $?)"
[ -z "${ACTUAL}" ] || die "expected empty output for comment-only alias file, got >${ACTUAL}<"
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
rm -f ../../../alias/test-edge-comments
+22
View File
@@ -0,0 +1,22 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with an embedded NUL byte after the version.
# NUL handling varies by shell: some stop at NUL, others read through it.
# The function must not crash, and must emit output starting with the version.
printf 'v22.1.0\000garbage\n' > ../../../alias/test-edge-nul
ACTUAL="$(nvm_alias test-edge-nul)"
EXIT_CODE=$?
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
case "${ACTUAL}" in
v22.1.0*) ;; # OK — starts with the version regardless of NUL handling
*) die "expected output starting with >v22.1.0<, got >${ACTUAL}<" ;;
esac
rm -f ../../../alias/test-edge-nul
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an empty alias file
printf '' > ../../../alias/test-edge-empty
ACTUAL="$(nvm_alias test-edge-empty 2>/dev/null)"
EXIT_CODE="$(nvm_alias test-edge-empty 2>/dev/null; echo $?)"
[ -z "${ACTUAL}" ] || die "expected empty output for empty alias file, got >${ACTUAL}<"
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
rm -f ../../../alias/test-edge-empty
@@ -0,0 +1,22 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with trailing form feed
printf 'v22.1.0\f\n' > ../../../alias/test-edge-ff
ACTUAL="$(nvm_alias test-edge-ff)"
EXPECTED='v22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for form feed, got >${ACTUAL}<"
# Create an alias file with trailing vertical tab
printf 'v22.2.0\v\n' > ../../../alias/test-edge-vt
ACTUAL="$(nvm_alias test-edge-vt)"
EXPECTED='v22.2.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for vertical tab, got >${ACTUAL}<"
rm -f ../../../alias/test-edge-ff ../../../alias/test-edge-vt
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with no trailing newline
printf 'v22.1.0' > ../../../alias/test-edge-no-newline
ACTUAL="$(nvm_alias test-edge-no-newline)"
EXPECTED='v22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
rm -f ../../../alias/test-edge-no-newline
+38
View File
@@ -0,0 +1,38 @@
#!/bin/sh
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
chmod 644 ../../../alias/test-edge-unreadable 2>/dev/null
rm -f ../../../alias/test-edge-unreadable
}
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file that exists but can not be read
echo 'v0.0.1' > ../../../alias/test-edge-unreadable
chmod 000 ../../../alias/test-edge-unreadable
# root (and some containers) can read mode-000 files; nothing to assert there
if [ -r ../../../alias/test-edge-unreadable ]; then
cleanup
exit 0
fi
# like the sed/awk pipeline this replaced: empty output, success status, so
# that `nvm_ensure_default_set` does not overwrite an unreadable default alias
OUTPUT="$(nvm_alias test-edge-unreadable 2>/dev/null)"
EXIT_CODE=$?
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0 for unreadable alias file, got ${EXIT_CODE}"
[ -z "${OUTPUT}" ] || die "expected empty output for unreadable alias file, got >${OUTPUT}<"
STDERR="$(nvm_alias test-edge-unreadable 2>&1 >/dev/null)"
case "${STDERR}" in
*'not readable'*) ;;
*) die "expected a not-readable warning on stderr, got >${STDERR}<" ;;
esac
cleanup
+17
View File
@@ -0,0 +1,17 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with a very long line (version followed by a long comment)
LONG_COMMENT="$(printf '%0*d' 10000 0 | command tr '0' 'x')"
printf 'v22.1.0 #%s\n' "${LONG_COMMENT}" > ../../../alias/test-edge-long
ACTUAL="$(nvm_alias test-edge-long)"
EXPECTED='v22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
rm -f ../../../alias/test-edge-long
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias file with trailing spaces and tabs
printf '22.1.0 \t \n' > ../../../alias/test-edge-trailing-ws
ACTUAL="$(nvm_alias test-edge-trailing-ws)"
EXPECTED='22.1.0'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
rm -f ../../../alias/test-edge-trailing-ws
+74
View File
@@ -0,0 +1,74 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# 1-hop self-reference: alias points to itself
echo 'self' > '../../../alias/self'
ACTUAL="$(nvm_resolve_alias self)"
EXPECTED='∞'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for self-reference, got >${ACTUAL}<"
rm -f '../../../alias/self'
# Multi-hop loop: link1 -> link2 -> link3 -> link1
echo 'link2' > '../../../alias/link1'
echo 'link3' > '../../../alias/link2'
echo 'link1' > '../../../alias/link3'
ACTUAL="$(nvm_resolve_alias link1)"
EXPECTED='∞'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for 3-hop cycle, got >${ACTUAL}<"
rm -f '../../../alias/link1' '../../../alias/link2' '../../../alias/link3'
# Cycle through an alias name containing a space
echo 'midway' > '../../../alias/foo bar'
echo 'foo bar' > '../../../alias/midway'
ACTUAL="$(nvm_resolve_alias 'foo bar')"
EXPECTED='∞'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for space-name cycle, got >${ACTUAL}<"
rm -f '../../../alias/foo bar' '../../../alias/midway'
# Non-cycle through an alias name containing a space.
# Guards the newline-delimited SEEN_ALIASES storage: with space- or
# token-delimited storage, seen name 'foo bar' would falsely match 'bar'.
# Resolves: 'foo bar' -> 'midway' -> 'bar' -> 0.0.99
echo 'midway' > '../../../alias/foo bar'
echo 'bar' > '../../../alias/midway'
echo '0.0.99' > '../../../alias/bar'
ACTUAL="$(nvm_resolve_alias 'foo bar')"
EXPECTED='v0.0.99'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for space-name chain, got >${ACTUAL}<"
rm -f '../../../alias/foo bar' '../../../alias/midway' '../../../alias/bar'
# Non-cycle through an alias name containing a regex metacharacter.
# Guards the literal `case` matching: the previous grep-based detection
# interpolated the resolved name into an anchored regex, so resolving 'axb'
# matched the seen name 'axb' against the pattern 'a.b' and falsely
# reported a cycle.
# Resolves: 'axb' -> 'a.b' -> 0.0.99
echo 'a.b' > '../../../alias/axb'
echo '0.0.99' > '../../../alias/a.b'
ACTUAL="$(nvm_resolve_alias axb)"
EXPECTED='v0.0.99'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for metachar-name chain, got >${ACTUAL}<"
# ... while a genuine cycle through a metachar name is still detected
echo 'axb' > '../../../alias/a.b'
ACTUAL="$(nvm_resolve_alias axb)"
EXPECTED='∞'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for metachar-name cycle, got >${ACTUAL}<"
rm -f '../../../alias/axb' '../../../alias/a.b'
+20
View File
@@ -0,0 +1,20 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create a 4-deep alias chain: hop1 -> hop2 -> hop3 -> hop4 -> 0.0.99
echo 'hop2' > ../../../alias/hop1
echo 'hop3' > ../../../alias/hop2
echo 'hop4' > ../../../alias/hop3
echo '0.0.99' > ../../../alias/hop4
ACTUAL="$(nvm_resolve_alias hop1)"
EXPECTED='v0.0.99'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}< for 4-deep chain, got >${ACTUAL}<"
rm -f ../../../alias/hop1 ../../../alias/hop2 ../../../alias/hop3 ../../../alias/hop4
@@ -0,0 +1,19 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../../.. && pwd)"
: nvm.sh
\. "${NVM_DIR}/nvm.sh"
# Create an alias pointing to a version that does not exist as an alias
echo '99.99.99' > ../../../alias/test-edge-noexist
ACTUAL="$(nvm_resolve_alias test-edge-noexist)"
EXPECTED='v99.99.99'
EXIT_CODE="$(nvm_resolve_alias test-edge-noexist >/dev/null 2>&1; echo $?)"
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
[ "${EXIT_CODE}" = '0' ] || die "expected exit code 0, got ${EXIT_CODE}"
rm -f ../../../alias/test-edge-noexist
+5
View File
@@ -17,3 +17,8 @@ rm -f "../../../alias/iojs"
rm -f "../../../alias/default" rm -f "../../../alias/default"
rm -f "../../../alias/test-blank-lines" rm -f "../../../alias/test-blank-lines"
rm -f "../../../alias/test-multi-lines" rm -f "../../../alias/test-multi-lines"
rm -f "../../../alias/test-edge-"* "../../../alias/test edge spaces"
rm -f "../../../alias/self" "../../../alias/link1" "../../../alias/link2" "../../../alias/link3"
rm -f "../../../alias/foo bar" "../../../alias/midway" "../../../alias/bar"
rm -f "../../../alias/hop1" "../../../alias/hop2" "../../../alias/hop3" "../../../alias/hop4"
rm -f "../../../alias/axb" "../../../alias/a.b"
@@ -0,0 +1,44 @@
#!/bin/sh
set -e
die () { echo "$@" ; exit 1; }
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
HELP="$(nvm --help 2>&1)"
# Signatures for use/exec/run advertise `current` (mirroring `nvm which`).
for EXPECTED in \
'nvm use [current | <version>]' \
'nvm exec [current | <version>] [<command>]' \
'nvm run [current | <version>] [<args>]' \
'nvm which [current | <version>]' \
; do
case "${HELP}" in
*"${EXPECTED}"*) ;;
*) die "nvm --help did not contain signature >${EXPECTED}<" ;;
esac
done
# The .nvmrc fallback is documented as conditional, not free.
case "${HELP}" in
*'Uses .nvmrc if version is omitted; otherwise errors.'*) ;;
*) die "nvm --help did not document the .nvmrc fallback caveat" ;;
esac
# The stale, looser phrasing must be gone.
case "${HELP}" in
*'if available and version is omitted'*) die "nvm --help still contains the old .nvmrc phrasing" ;;
esac
# `nvm current` is documented as resolving via \$PATH, not .nvmrc.
case "${HELP}" in
*'Display the active node version (resolved via $PATH; not affected by .nvmrc).'*) ;;
*) die "nvm --help did not document that 'nvm current' resolves via \$PATH" ;;
esac
@@ -0,0 +1,63 @@
#!/bin/sh
set -ex
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so no ambient .nvmrc above the test dir
# can satisfy the lookup and mask the warning.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
EXEC_WARNING='WARNING: `nvm exec` was invoked without a version argument and without an .nvmrc file.'
RUN_WARNING='WARNING: `nvm run` was invoked without a version argument and without an .nvmrc file.'
# `nvm exec` with no version and no .nvmrc should warn on stderr (and fall back).
set +ex # needed for stderr
EXEC_STDERR="$(nvm exec </dev/null 2>&1 1>/dev/null)"
set -ex
case "${EXEC_STDERR}" in
*"${EXEC_WARNING}"*) ;;
*) die "'nvm exec' with no version did not warn; got >${EXEC_STDERR}<" ;;
esac
# `--silent` should suppress the warning.
set +ex # needed for stderr
EXEC_SILENT_STDERR="$(nvm exec --silent </dev/null 2>&1 1>/dev/null)"
set -ex
case "${EXEC_SILENT_STDERR}" in
*WARNING*) die "'nvm exec --silent' should not warn; got >${EXEC_SILENT_STDERR}<" ;;
esac
# `nvm run` with an unresolvable version and no .nvmrc should warn (and fall back).
set +ex # needed for stderr
RUN_STDERR="$(nvm run bogusversion </dev/null 2>&1 1>/dev/null)"
set -ex
case "${RUN_STDERR}" in
*"${RUN_WARNING}"*) ;;
*) die "'nvm run' with no resolvable version did not warn; got >${RUN_STDERR}<" ;;
esac
# `--silent` should suppress the warning.
set +ex # needed for stderr
RUN_SILENT_STDERR="$(nvm run --silent bogusversion </dev/null 2>&1 1>/dev/null)"
set -ex
case "${RUN_SILENT_STDERR}" in
*WARNING*) die "'nvm run --silent' should not warn; got >${RUN_SILENT_STDERR}<" ;;
esac
cleanup
@@ -0,0 +1,68 @@
#!/bin/sh
set -ex
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
export NVM_DIR="$(cd ../.. && pwd)"
: nvm.sh
\. ../../nvm.sh
\. ../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so the "no version + no .nvmrc" cases
# (install/run/which) are not masked by an ambient .nvmrc above the test dir.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
# Asserts a subcommand emits the given focused usage line (not the full help
# dump) on stderr, and exits 127.
assert_usage() {
local EXPECTED_LINE
EXPECTED_LINE="$1"
shift
try_err "$@"
case "${CAPTURED_STDERR}" in
*"${EXPECTED_LINE}"*) ;;
*) die "\`$*\` did not show focused usage >${EXPECTED_LINE}<; got >${CAPTURED_STDERR}<" ;;
esac
# the focused usage should NOT be the full help dump
case "${CAPTURED_STDERR}" in
*'Show this message'*) die "\`$*\` dumped full help instead of a focused usage" ;;
esac
[ "_${CAPTURED_EXIT_CODE}" = "_127" ] \
|| die "\`$*\` expected exit code 127; got ${CAPTURED_EXIT_CODE}"
}
assert_usage 'Usage: nvm cache dir' nvm cache bogus
assert_usage 'Usage: nvm install [<version>]' nvm install
assert_usage 'Usage: nvm run [<version>] [<args>]' nvm run
assert_usage 'Usage: nvm which [current | <version>]' nvm which
assert_usage 'Usage: nvm uninstall <version>' nvm uninstall
assert_usage 'Usage: nvm uninstall <version>' nvm uninstall a b
assert_usage 'Usage: nvm unalias <name>' nvm unalias
assert_usage 'Usage: nvm unalias <name>' nvm unalias a b
assert_usage 'Usage: nvm install-latest-npm' nvm install-latest-npm extra
assert_usage 'Usage: nvm reinstall-packages <version>' nvm reinstall-packages
assert_usage 'Usage: nvm copy-packages <version>' nvm copy-packages a b
# `nvm use` reaches its focused-usage guard only when version resolution returns
# an empty string. From the CLI that cannot happen: an omitted version is caught
# earlier (the `Please see ... nvmrc` branch), and an unresolvable non-empty
# version yields the "N/A" sentinel, never "". The branch is a defensive guard,
# so drive it directly by stubbing the resolver to return empty. Keep this last:
# the stub stays in effect for the rest of the shell.
nvm_match_version() { nvm_echo ''; }
assert_usage 'Usage: nvm use [<version>]' nvm use foo
cleanup
+6 -3
View File
@@ -12,8 +12,10 @@ nvm_download() {
} }
# --offline with an already-installed version should succeed # --offline with an already-installed version should succeed
INSTALLED_VERSION="$(nvm ls | command tail -1 | command awk '{print $1}' | command sed 's/\x1b\[[0-9;]*m//g')" # (`nvm ls` ends with the alias listing, so use `nvm_ls`, which emits bare
if [ -n "${INSTALLED_VERSION}" ] && [ "_${INSTALLED_VERSION}" != '_N/A' ] && [ "_${INSTALLED_VERSION}" != '_system' ]; then # versions, and skip its trailing `system <version>` line)
INSTALLED_VERSION="$(nvm_ls | command grep -v '^system' | command tail -n1)"
if [ -n "${INSTALLED_VERSION}" ] && [ "_${INSTALLED_VERSION}" != '_N/A' ]; then
try nvm install --offline "${INSTALLED_VERSION}" try nvm install --offline "${INSTALLED_VERSION}"
[ "_$CAPTURED_EXIT_CODE" = "_0" ] \ [ "_$CAPTURED_EXIT_CODE" = "_0" ] \
|| die "nvm install --offline with installed version '${INSTALLED_VERSION}' should succeed, got exit code $CAPTURED_EXIT_CODE" || die "nvm install --offline with installed version '${INSTALLED_VERSION}' should succeed, got exit code $CAPTURED_EXIT_CODE"
@@ -30,9 +32,10 @@ nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "${EXPECTED_ERR}" \
# --offline should not require curl or wget # --offline should not require curl or wget
nvm_has() { return 1; } nvm_has() { return 1; }
nvm_has_executable() { return 1; }
try_err nvm install --offline 999.999.999 try_err nvm install --offline 999.999.999
# Should fail with "not found" not "nvm needs curl or wget" # Should fail with "not found" not "nvm needs curl or wget"
nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \ nvm_echo "$CAPTURED_STDERR" | nvm_grep -q "curl or wget" \
&& die "nvm install --offline should not require curl or wget" && die "nvm install --offline should not require curl or wget"
alias nvm_has='\nvm_has' alias nvm_has='\nvm_has'
unset -f nvm_has unset -f nvm_has nvm_has_executable
+18 -18
View File
@@ -1,7 +1,11 @@
#!/bin/sh #!/bin/sh
WORK="$PWD/nvm_curl_libz_support-work.$$"
TEST_BIN="$WORK/bin"
cleanup() { cleanup() {
unset -f curl rm -rf "$WORK"
export PATH="$OLDPATH"
} }
die() { cleanup; echo "$@" ; exit 1; } die() { cleanup; echo "$@" ; exit 1; }
@@ -9,32 +13,28 @@ die() { cleanup; echo "$@" ; exit 1; }
: nvm.sh : nvm.sh
\. ../../../nvm.sh \. ../../../nvm.sh
curl() { \. ../../common.sh
# curl with libz feature
if [ $# -ne 1 ] || [ "$1" != "-V" ]; then OLDPATH="$PATH"
die "This fake curl only takes one parameter -V"
fi make_fake_curl "$TEST_BIN"
echo "
export PATH="$TEST_BIN:$OLDPATH"
# curl with libz feature
VERSION_MESSAGE="
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3 curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets" Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
}
nvm_curl_libz_support || die "nvm_curl_libz_support should return 0" nvm_curl_libz_support || die "nvm_curl_libz_support should return 0"
unset -f curl # curl without libz feature
VERSION_MESSAGE="
curl() {
# curl without libz feature
if [ "$#" -ne 1 ] || [ "$1" != "-V" ]; then
die "This fake curl only takes one parameter -V"
fi
echo "
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.32 curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.32
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL TLS-SRP UnixSockets" Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL TLS-SRP UnixSockets"
}
! nvm_curl_libz_support || die "nvm_curl_libz_support should return 1" ! nvm_curl_libz_support || die "nvm_curl_libz_support should return 1"
unset -f curl cleanup
+12 -5
View File
@@ -1,18 +1,25 @@
#!/bin/sh #!/bin/sh
WORK="$PWD/nvm_curl_use_compression-work.$$"
TEST_BIN="$WORK/bin"
cleanup () { cleanup () {
unset -f die unset -f die
rm -rf "$WORK"
export PATH="$OLDPATH"
} }
die () { echo -e "$@" ; cleanup ; exit 1; } die () { echo -e "$@" ; cleanup ; exit 1; }
NVM_ENV=testing \. ../../../nvm.sh NVM_ENV=testing \. ../../../nvm.sh
curl() { \. ../../common.sh
if [ "$1" = "-V" ]; then
echo "${VERSION_MESSAGE}" OLDPATH="$PATH"
fi
} make_fake_curl "$TEST_BIN"
export PATH="$TEST_BIN:$OLDPATH"
CURL_VERSION_ON_ARCHLINUX_WITH_LIBZ="curl 7.54.0 (x86_64-pc-linux-gnu) libcurl/7.54.0 OpenSSL/1.1.0f zlib/1.2.11 libpsl/0.17.0 (+libicu/59.1) libssh2/1.8.0 nghttp2/1.22.0 CURL_VERSION_ON_ARCHLINUX_WITH_LIBZ="curl 7.54.0 (x86_64-pc-linux-gnu) libcurl/7.54.0 OpenSSL/1.1.0f zlib/1.2.11 libpsl/0.17.0 (+libicu/59.1) libssh2/1.8.0 nghttp2/1.22.0
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
+13 -7
View File
@@ -1,19 +1,25 @@
#!/bin/sh #!/bin/sh
WORK="$PWD/nvm_curl_version-work.$$"
TEST_BIN="$WORK/bin"
cleanup () { cleanup () {
unset -f die unset -f die cleanup assert_version_is
unset -f curl rm -rf "$WORK"
export PATH="$OLDPATH"
} }
die () { echo -e "$@" ; cleanup ; exit 1; } die () { echo -e "$@" ; cleanup ; exit 1; }
NVM_ENV=testing \. ../../../nvm.sh NVM_ENV=testing \. ../../../nvm.sh
curl() { \. ../../common.sh
if [ "$1" = "-V" ]; then
echo "${VERSION_MESSAGE}" OLDPATH="$PATH"
fi
} make_fake_curl "$TEST_BIN"
export PATH="$TEST_BIN:$OLDPATH"
assert_version_is() { assert_version_is() {
if [ "${1}" != "${2}" ]; then if [ "${1}" != "${2}" ]; then
@@ -0,0 +1,66 @@
#!/bin/sh
WORK="$PWD/shadowed-curl-work.$$"
TEST_BIN="$WORK/bin"
ARGV_LOG="$WORK/argv.log"
cleanup () {
unset -f die cleanup curl wget
rm -rf "$WORK"
export PATH="$OLDPATH"
}
die () { echo "$@" ; cleanup ; exit 1; }
NVM_ENV=testing \. ../../../nvm.sh
\. ../../common.sh
OLDPATH="$PATH"
# real-looking curl on PATH; calling the shadowing shell function below instead is a failure
make_fake_curl "$TEST_BIN" ': > "$ARGV_LOG"
for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
VERSION_MESSAGE="curl 7.99.0 (fake)
Features: libz"
export ARGV_LOG
export PATH="$TEST_BIN:$OLDPATH"
# shadowing shell functions, like aliases baked into a user's shell, must be
# bypassed in favor of the executables on PATH (https://github.com/nvm-sh/nvm/issues/2923)
curl() {
echo 'curl 0.0.0-shadowed'
return 1
}
wget() {
return 1
}
[ "$(nvm_curl_version)" = '7.99.0' ] || die "nvm_curl_version used the shadowing curl function; got $(nvm_curl_version)"
nvm_curl_libz_support || die 'nvm_curl_libz_support used the shadowing curl function'
nvm_download -s 'http://example.com/' -o /dev/null || die 'nvm_download used the shadowing curl function and failed'
grep -Fxq 'http://example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the curl executable; got: $(cat "$ARGV_LOG")"
# when no curl executable exists, a shadowing curl shell function must not fool
# downloader selection: nvm_download must fall back to the wget executable
WGET_ONLY_BIN="$WORK/wget-only-bin"
mkdir -p "$WGET_ONLY_BIN"
{
echo '#!/bin/sh'
echo ': > "$ARGV_LOG"'
echo 'for a in "$@"; do printf "%s\n" "$a" >> "$ARGV_LOG"; done'
} > "$WGET_ONLY_BIN/wget"
chmod +x "$WGET_ONLY_BIN/wget"
(
PATH="$WGET_ONLY_BIN"
export PATH
nvm_download -s 'http://wget-fallback.example.com/' -o /dev/null
) || die 'nvm_download did not fall back to wget when curl is only a shell function'
grep -Fxq 'http://wget-fallback.example.com/' "$ARGV_LOG" || die "nvm_download did not invoke the wget executable; got: $(cat "$ARGV_LOG")"
cleanup
@@ -6,7 +6,7 @@ TEST_BIN="$WORK/bin"
ARGV_LOG="$WORK/argv.log" ARGV_LOG="$WORK/argv.log"
cleanup() { cleanup() {
unset -f die cleanup nvm_has unset -f die cleanup nvm_has_executable
rm -rf "$WORK" rm -rf "$WORK"
export PATH="$OLDPATH" export PATH="$OLDPATH"
} }
@@ -30,7 +30,7 @@ chmod +x "$TEST_BIN/wget"
export ARGV_LOG export ARGV_LOG
export PATH="$TEST_BIN:$OLDPATH" export PATH="$TEST_BIN:$OLDPATH"
# force the wget path while keeping system tools (sed) available for sanitization # force the wget path while keeping system tools (sed) available for sanitization
nvm_has() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; } nvm_has_executable() { [ "$1" != curl ] && command -v "$1" >/dev/null 2>&1; }
# given an Authorization credential in NVM_AUTH_HEADER # given an Authorization credential in NVM_AUTH_HEADER
# when nvm_download uses the wget path # when nvm_download uses the wget path
+9 -2
View File
@@ -90,7 +90,14 @@ run_test amd64 smartos x64 no_pkg_info
run_test x86 osx x86 run_test x86 osx x86
run_test amd64 osx x64 run_test amd64 osx x64
run_test arm64 smartos x64 # These smartos cases have no arch-specific uname mock, so nvm_get_os falls
run_test armv8l smartos x64 # through to the real host; on Alpine that host is linux and picks up the musl
# suffix, which these non-musl assertions do not expect. Skip them there.
if [ ! -f "/etc/alpine-release" ]; then
run_test arm64 smartos x64
run_test armv8l smartos x64
fi
run_test loongarch64 linux loong64
cleanup cleanup
+4 -4
View File
@@ -15,8 +15,8 @@ die () { cleanup; echo "$@" ; exit 1; }
MOCKS_DIR="$(pwd)/../../mocks" MOCKS_DIR="$(pwd)/../../mocks"
export PATH=".:${PATH}" export PATH=".:${PATH}"
# On Alpine (where /etc/alpine-release exists), x64 should get -musl suffix # On Alpine (where /etc/alpine-release exists), both x64 and arm64 should get
# and arm64 should NOT get -musl suffix. # the -musl suffix, since unofficial-builds publishes musl binaries for both.
# On non-Alpine, neither should get -musl. # On non-Alpine, neither should get -musl.
if [ -f "/etc/alpine-release" ]; then if [ -f "/etc/alpine-release" ]; then
@@ -26,11 +26,11 @@ if [ -f "/etc/alpine-release" ]; then
rm -f ./uname rm -f ./uname
[ "_${OUTPUT}" = "_x64-musl" ] || die "x64 on Alpine should be x64-musl, got ${OUTPUT}" [ "_${OUTPUT}" = "_x64-musl" ] || die "x64 on Alpine should be x64-musl, got ${OUTPUT}"
# aarch64 on Alpine should produce arm64, NOT arm64-musl # aarch64 on Alpine should produce arm64-musl
ln -sf "${MOCKS_DIR}/uname_linux_aarch64" ./uname ln -sf "${MOCKS_DIR}/uname_linux_aarch64" ./uname
OUTPUT="$(nvm_get_arch)" OUTPUT="$(nvm_get_arch)"
rm -f ./uname rm -f ./uname
[ "_${OUTPUT}" = "_arm64" ] || die "aarch64 on Alpine should be arm64 (no musl suffix), got ${OUTPUT}" [ "_${OUTPUT}" = "_arm64-musl" ] || die "aarch64 on Alpine should be arm64-musl, got ${OUTPUT}"
else else
# x64 on non-Alpine should produce x64 (no musl suffix) # x64 on non-Alpine should produce x64 (no musl suffix)
ln -sf "${MOCKS_DIR}/uname_linux_x86_64" ./uname ln -sf "${MOCKS_DIR}/uname_linux_x86_64" ./uname
+15 -7
View File
@@ -57,15 +57,23 @@ setup_chroot() {
sudo mknod "${chroot_dir}/dev/null" c 1 3 sudo mknod "${chroot_dir}/dev/null" c 1 3
} }
setup_chroot "${CHROOT_WITH_ALPINE}" # The chroot fixtures assume a glibc layout (fixed dynamic-linker path under
setup_chroot "${CHROOT_WITHOUT_ALPINE}" # /lib64, coreutils binaries). On musl Alpine that setup does not apply, and
# nvm_get_arch's musl mapping is already covered by the "nvm_get_arch alpine"
# test, so skip the chroot checks there and still run the ls-remote checks.
if [ -f "/etc/alpine-release" ]; then
echo "on Alpine; skipping chroot arch checks (covered by 'nvm_get_arch alpine')"
else
setup_chroot "${CHROOT_WITH_ALPINE}"
setup_chroot "${CHROOT_WITHOUT_ALPINE}"
# Run tests in chroot environments # Run tests in chroot environments
ARCH_WITH_ALPINE=$(sudo chroot "${CHROOT_WITH_ALPINE}" /bin/sh -c ". ./nvm.sh && nvm_get_arch") ARCH_WITH_ALPINE=$(sudo chroot "${CHROOT_WITH_ALPINE}" /bin/sh -c ". ./nvm.sh && nvm_get_arch")
[ "${ARCH_WITH_ALPINE}" = "x64-musl" ] || die "Expected x64-musl for alpine environment but got ${ARCH_WITH_ALPINE}" [ "${ARCH_WITH_ALPINE}" = "x64-musl" ] || die "Expected x64-musl for alpine environment but got ${ARCH_WITH_ALPINE}"
ARCH_WITHOUT_ALPINE=$(sudo chroot "${CHROOT_WITHOUT_ALPINE}" /bin/sh -c ". ./nvm.sh && nvm_get_arch") ARCH_WITHOUT_ALPINE=$(sudo chroot "${CHROOT_WITHOUT_ALPINE}" /bin/sh -c ". ./nvm.sh && nvm_get_arch")
[ "${ARCH_WITHOUT_ALPINE}" != "x64-musl" ] || die "Did not expect x64-musl for non-alpine environment" [ "${ARCH_WITHOUT_ALPINE}" != "x64-musl" ] || die "Did not expect x64-musl for non-alpine environment"
fi
# Run tests for nvm ls-remote # Run tests for nvm ls-remote
test_default_ls_remote() { test_default_ls_remote() {
@@ -110,3 +110,26 @@ ACTUAL="$(nvm_get_download_slug iojs source 15.99.99)"
EXPECTED="iojs-15.99.99" EXPECTED="iojs-15.99.99"
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<" [ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
REAL_OS="$(command uname -s 2>/dev/null || echo '')"
REAL_ARCH="$(command uname -m 2>/dev/null || echo '')"
if [ "${REAL_OS}" = "Darwin" ] && [ "${REAL_ARCH}" = "arm64" ]; then
# Node < 16 uses x64 on darwin-arm64
ACTUAL="$(nvm_get_download_slug node binary 14.21.3)"
EXPECTED='node-14.21.3-darwin-x64'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
ACTUAL="$(nvm_get_download_slug node binary 15.99.99)"
EXPECTED='node-15.99.99-darwin-x64'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
ACTUAL="$(nvm_get_download_slug iojs binary 15.99.99)"
EXPECTED='iojs-15.99.99-darwin-x64'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
# Test Node >= 16 uses arm64 on darwin-arm64
ACTUAL="$(nvm_get_download_slug node binary 16.0.0)"
EXPECTED='node-16.0.0-darwin-arm64'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
ACTUAL="$(nvm_get_download_slug node binary 18.0.0)"
EXPECTED='node-18.0.0-darwin-arm64'
[ "${ACTUAL}" = "${EXPECTED}" ] || die "expected >${EXPECTED}<, got >${ACTUAL}<"
fi
@@ -3,7 +3,7 @@
die () { echo "$@" ; cleanup ; exit 1; } die () { echo "$@" ; cleanup ; exit 1; }
cleanup() { cleanup() {
unset -f nvm_has unset -f nvm_has nvm_has_executable
} }
: nvm.sh : nvm.sh
@@ -12,6 +12,7 @@ cleanup() {
\. ../../common.sh \. ../../common.sh
nvm_has() { return 1 ; } nvm_has() { return 1 ; }
nvm_has_executable() { return 1 ; }
try_err nvm_get_latest try_err nvm_get_latest
[ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \ [ "_$CAPTURED_STDERR" = "_nvm needs curl or wget to proceed." ] \
@@ -14,6 +14,14 @@ die () { >&2 echo "$@" ; cleanup ; exit 1; }
: nvm.sh : nvm.sh
\. ../../../nvm.sh \. ../../../nvm.sh
# v0.12.18 predates musl binaries and the expected output hardcodes the glibc
# x64 tarball URL, so on Alpine nvm would request a nonexistent -musl build.
# The progress-bar behavior is not OS-specific, so skip below the musl floor.
if [ -f "/etc/alpine-release" ]; then
echo 'on Alpine; skipping (v0.12.18 has no musl binary)'
exit 0
fi
cleanup cleanup
OUTPUT="$(TERM=dumb 2>&1 nvm install --no-progress v0.12.18)" OUTPUT="$(TERM=dumb 2>&1 nvm install --no-progress v0.12.18)"
@@ -1,10 +1,24 @@
#!/bin/sh #!/bin/sh
die () { echo "$@" ; exit 1; } die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
rm -rf "${TEST_DIR-}"
unset NVMRC_CONTENT OUTPUT EXIT_CODE TEST_DIR NVM_DIR
}
: nvm.sh : nvm.sh
\. ../../../nvm.sh \. ../../../nvm.sh
\. ../../common.sh
# an isolated NVM_DIR with a single known version, so that ambient versions
# and aliases can not affect any assertions
TEST_DIR="${PWD}/nvm_ls_hash_pattern_tmp"
mkdir -p "${TEST_DIR}/versions/node/v24.13.0/bin" || die 'failed to create test version dir'
make_echo "${TEST_DIR}/versions/node/v24.13.0/bin/node" 'v24.13.0' || die 'failed to create test node binary'
NVM_DIR="${TEST_DIR}"
# Test: nvm_ls with pattern containing # should not cause sed error # Test: nvm_ls with pattern containing # should not cause sed error
# This is a regression test for https://github.com/nvm-sh/nvm/issues/3761 # This is a regression test for https://github.com/nvm-sh/nvm/issues/3761
@@ -22,3 +36,33 @@ echo "$OUTPUT" | grep -q "invalid command code" && \
# Should return N/A with exit code 3 (not found) # Should return N/A with exit code 3 (not found)
[ "$EXIT_CODE" = "3" ] || die "nvm_ls 'foo#bar' should exit with code 3, got $EXIT_CODE" [ "$EXIT_CODE" = "3" ] || die "nvm_ls 'foo#bar' should exit with code 3, got $EXIT_CODE"
echo "$OUTPUT" | grep -q "N/A" || die "nvm_ls 'foo#bar' should output N/A, got: $OUTPUT" echo "$OUTPUT" | grep -q "N/A" || die "nvm_ls 'foo#bar' should output N/A, got: $OUTPUT"
NVMRC_CONTENT='v24.13.0
# krypton is the codename for Node.js v24.x'
OUTPUT="$(nvm_ls "${NVMRC_CONTENT}" 2>&1)"
EXIT_CODE=$?
[ "$EXIT_CODE" = "0" ] || die "nvm_ls with .nvmrc comments should exit with code 0, got $EXIT_CODE"
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_ls with .nvmrc comments should output v24.13.0, got: $OUTPUT"
OUTPUT="$(nvm_version "${NVMRC_CONTENT}" 2>&1)"
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_version with .nvmrc comments should output v24.13.0, got: $OUTPUT"
# a partial version reaches nvm_ls's find/sed pipeline, which is where multiline
# patterns used to break sed ("unterminated regular expression" on BSD sed,
# "unterminated address regex" on GNU sed); a full x.y.z version takes the
# explicit-version fast path and never reaches it
NVMRC_CONTENT='24
# krypton is the codename for Node.js v24.x'
OUTPUT="$(nvm_ls "${NVMRC_CONTENT}" 2>&1)"
EXIT_CODE=$?
echo "$OUTPUT" | grep -q "unterminated" && \
die "nvm_ls with partial version + comments caused a sed error: $OUTPUT"
[ "$EXIT_CODE" = "0" ] || die "nvm_ls with partial version + comments should exit with code 0, got $EXIT_CODE"
[ "$OUTPUT" = "v24.13.0" ] || die "nvm_ls with partial version + comments should output v24.13.0, got: $OUTPUT"
cleanup
+40
View File
@@ -0,0 +1,40 @@
#!/bin/sh
WORK="$PWD/ls_remote-traversal-work.$$"
export HOME="$WORK/home"
export NVM_DIR="$HOME/.nvm"
BASHRC="$HOME/.bashrc"
cleanup() {
unset -f die cleanup nvm_download
rm -rf "$WORK"
}
die () { echo "$@" ; cleanup ; exit 1; }
mkdir -p "$NVM_DIR/alias"
: nvm.sh
\. ../../../nvm.sh
# a malicious/compromised mirror: the LTS codename field ($10) carries path
# traversal, and the version field ($1) carries a command-substitution payload;
# a valid codename (Iron) is included to prove real aliases still get written
nvm_download() {
printf 'version\tdate\tfiles\tnpm\tv8\tuv\tzlib\topenssl\tmodules\tlts\tsecurity\n'
printf '$(>%s/pwned)\t2026-01-01\tlinux-x64\t-\t-\t-\t-\t-\t-\t../../../.bashrc\t-\n' "$WORK"
printf 'v20.0.0\t2026-01-01\tlinux-x64\t-\t-\t-\t-\t-\t-\tIron\t-\n'
}
nvm_ls_remote >/dev/null 2>&1 || true
[ ! -e "$BASHRC" ] || die "path traversal wrote outside the alias dir: $BASHRC was created"
[ ! -e "$WORK/pwned" ] || die "mirror-supplied payload landed: $WORK/pwned was created"
[ -f "$NVM_DIR/alias/lts/iron" ] || die "valid LTS alias lts/iron was not created"
nvm_make_alias 'lts/../../../escape' 'v1.0.0' 2>/dev/null && die 'nvm_make_alias accepted a traversing alias name'
[ ! -e "$NVM_DIR/../escape" ] || die 'nvm_make_alias wrote outside the alias dir'
nvm_make_alias 'lts/carbon' 'v8.0.0' >/dev/null 2>&1 || die 'nvm_make_alias rejected a valid alias name'
[ -f "$NVM_DIR/alias/lts/carbon" ] || die 'nvm_make_alias did not create a valid alias'
cleanup
echo "nvm_ls_remote LTS codename traversal: passed"
+33
View File
@@ -10,6 +10,10 @@ TEST_DIR="$(pwd)/nvm_offline_version_tmp"
cleanup() { cleanup() {
rm -rf "${TEST_DIR}" rm -rf "${TEST_DIR}"
CACHE_DIR="$(nvm_cache_dir)"
SUFFIX="$(nvm_get_os)-$(nvm_get_arch)"
rm -rf "${CACHE_DIR}/bin/node-v0.99.98-${SUFFIX}" "${CACHE_DIR}/bin/iojs-v0.99.97-${SUFFIX}" \
"${CACHE_DIR}/src/node-v0.99.96" "${CACHE_DIR}/src/iojs-v0.99.95"
} }
[ ! -e "${TEST_DIR}" ] && mkdir -p "${TEST_DIR}" [ ! -e "${TEST_DIR}" ] && mkdir -p "${TEST_DIR}"
@@ -36,4 +40,33 @@ try nvm_ls_cached "999.999"
[ -z "$CAPTURED_STDOUT" ] \ [ -z "$CAPTURED_STDOUT" ] \
|| die "nvm_ls_cached '999.999' should return empty; got '$CAPTURED_STDOUT'" || die "nvm_ls_cached '999.999' should return empty; got '$CAPTURED_STDOUT'"
# nvm_ls_cached should list bin- and src-cached artifacts, for node and io.js
CACHE_DIR="$(nvm_cache_dir)"
SUFFIX="$(nvm_get_os)-$(nvm_get_arch)"
mkdir -p "${CACHE_DIR}/bin/node-v0.99.98-${SUFFIX}" "${CACHE_DIR}/bin/iojs-v0.99.97-${SUFFIX}" \
"${CACHE_DIR}/src/node-v0.99.96" "${CACHE_DIR}/src/iojs-v0.99.95"
try nvm_ls_cached "v0.99.98"
[ "_$CAPTURED_STDOUT" = "_v0.99.98" ] \
|| die "nvm_ls_cached 'v0.99.98' should find the bin-cached node version; got '$CAPTURED_STDOUT'"
try nvm_ls_cached "iojs-v0.99.97"
[ "_$CAPTURED_STDOUT" = "_iojs-v0.99.97" ] \
|| die "nvm_ls_cached 'iojs-v0.99.97' should find the bin-cached io.js version; got '$CAPTURED_STDOUT'"
try nvm_ls_cached "v0.99.96"
[ "_$CAPTURED_STDOUT" = "_v0.99.96" ] \
|| die "nvm_ls_cached 'v0.99.96' should find the src-cached node version; got '$CAPTURED_STDOUT'"
try nvm_ls_cached "iojs-v0.99.95"
[ "_$CAPTURED_STDOUT" = "_iojs-v0.99.95" ] \
|| die "nvm_ls_cached 'iojs-v0.99.95' should find the src-cached io.js version; got '$CAPTURED_STDOUT'"
# ... and nvm_offline_version should resolve them
try nvm_offline_version "iojs-v0.99.95"
[ "_$CAPTURED_STDOUT" = "_iojs-v0.99.95" ] \
|| die "nvm_offline_version 'iojs-v0.99.95' should resolve the src-cached io.js version; got '$CAPTURED_STDOUT'"
[ "_$CAPTURED_EXIT_CODE" = "_0" ] \
|| die "nvm_offline_version 'iojs-v0.99.95' should exit 0; got '$CAPTURED_EXIT_CODE'"
cleanup cleanup
@@ -0,0 +1,39 @@
#!/bin/sh
die () { echo "$@" ; cleanup ; exit 1; }
cleanup() {
cd "${ORIG_PWD}" 2>/dev/null || true
[ -n "${TMP_DIR-}" ] && rm -rf "${TMP_DIR}"
}
: nvm.sh
\. ../../../nvm.sh
\. ../../common.sh
ORIG_PWD="$(pwd)"
# Run from a fresh, empty directory so no ambient .nvmrc above the test dir
# is found by the upward lookup.
TMP_DIR="$(mktemp -d)"
cd "${TMP_DIR}" || die "could not cd to temp dir"
# The message must name both halves of the problem: no argument AND no .nvmrc.
try_err nvm_rc_version
EXPECTED='No version provided and no .nvmrc file found'
[ "_${CAPTURED_STDERR}" = "_${EXPECTED}" ] \
|| die "nvm_rc_version did not print >${EXPECTED}<; got >${CAPTURED_STDERR}<"
[ "_${CAPTURED_EXIT_CODE}" = "_1" ] \
|| die "nvm_rc_version expected exit code 1; got ${CAPTURED_EXIT_CODE}"
# NVM_SILENT suppresses the message but the call still fails.
export NVM_SILENT=1
try_err nvm_rc_version
unset NVM_SILENT
[ -z "${CAPTURED_STDERR}" ] \
|| die "NVM_SILENT nvm_rc_version should be silent; got >${CAPTURED_STDERR}<"
[ "_${CAPTURED_EXIT_CODE}" = "_1" ] \
|| die "NVM_SILENT nvm_rc_version expected exit code 1; got ${CAPTURED_EXIT_CODE}"
cleanup
+38
View File
@@ -0,0 +1,38 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
\. ../../../nvm.sh
set -ex
# Test 1: all standard base64 characters (RFC 4648) are preserved
STANDARD_B64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
RESULT=$(nvm_sanitize_auth_header "${STANDARD_B64}")
[ "${RESULT}" = "${STANDARD_B64}" ] || die "FAIL: standard base64 chars were stripped. Got: '${RESULT}'"
# Test 2: all base64url characters (RFC 4648 §5) are preserved
B64URL="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_="
RESULT=$(nvm_sanitize_auth_header "${B64URL}")
[ "${RESULT}" = "${B64URL}" ] || die "FAIL: base64url chars were stripped. Got: '${RESULT}'"
# Test 3: a real JWT Bearer token (base64url-encoded header.payload.signature) is preserved
JWT_TOKEN="Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
RESULT=$(nvm_sanitize_auth_header "${JWT_TOKEN}")
[ "${RESULT}" = "${JWT_TOKEN}" ] || die "FAIL: JWT Bearer token chars were stripped. Got: '${RESULT}'"
# Test 4: Basic auth (base64-encoded user:pass) is preserved
BASIC_TOKEN="Basic dXNlcm5hbWU6cGFzc3dvcmQ="
RESULT=$(nvm_sanitize_auth_header "${BASIC_TOKEN}")
[ "${RESULT}" = "${BASIC_TOKEN}" ] || die "FAIL: Basic auth base64 token chars were stripped. Got: '${RESULT}'"
# Test 5: dangerous shell metacharacters are removed
DANGEROUS="Bearer token;\`evil\`-cmd \$(inject)"
RESULT=$(nvm_sanitize_auth_header "${DANGEROUS}")
case "${RESULT}" in
*";"*|*"\`"*|*'$'*|*"("*|*")"*)
die "FAIL: dangerous shell metacharacters survived sanitization. Got: '${RESULT}'"
;;
esac
echo "All nvm_sanitize_auth_header tests passed"
+2 -2
View File
@@ -32,9 +32,9 @@ fi
# Test 2: Verify that sanitized header still works for legitimate requests # Test 2: Verify that sanitized header still works for legitimate requests
# The sanitized header should only contain safe characters # The sanitized header should only contain safe characters
SANITIZED=$(nvm_sanitize_auth_header "${MALICIOUS_HEADER}") SANITIZED=$(nvm_sanitize_auth_header "${MALICIOUS_HEADER}")
# Verify that dangerous characters were removed # Verify that dangerous shell metacharacters were removed
case "${SANITIZED}" in case "${SANITIZED}" in
*";"*|*"touch"*|*"/tmp"*) *";"*|*'$'*|*"\`"*)
die "SECURITY FAILURE: Sanitization did not remove dangerous characters properly" die "SECURITY FAILURE: Sanitization did not remove dangerous characters properly"
;; ;;
esac esac
+15
View File
@@ -0,0 +1,15 @@
include config.mk
all: out/fake-bin
out/fake-bin: VERSION
mkdir -p out
printf '#!/bin/sh\necho %s\n' "$$(cat VERSION)" > out/fake-bin
chmod +x out/fake-bin
install: all
mkdir -p "$(PREFIX)/bin"
cp out/fake-bin "$(PREFIX)/bin/node"
cp out/fake-bin "$(PREFIX)/bin/iojs"
.PHONY: all install
+22
View File
@@ -0,0 +1,22 @@
#!/bin/sh
# a fake node/io.js `configure`, for source-install tests: real io.js (and
# old node) can no longer be compiled on modern toolchains (python 2
# `configure`, ancient V8), so source-install tests exercise nvm's entire
# source pipeline against this tiny stand-in instead.
PREFIX=''
while [ $# -gt 0 ]; do
case "${1}" in
--prefix=*) PREFIX="${1#--prefix=}" ;;
esac
shift
done
if [ -z "${PREFIX}" ]; then
echo 'configure: a --prefix is required' >&2
exit 1
fi
printf 'PREFIX = %s\n' "${PREFIX}" > config.mk
echo "configured with PREFIX=${PREFIX}"
+44
View File
@@ -0,0 +1,44 @@
#!/bin/sh
\. ../common.sh
die () { echo "$@" ; exit 1; }
\. ../../nvm.sh
set -ex
NVM_TEST_VERSION='v3.99.9'
NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}"
# Remove the stuff we're clobbering.
nvm uninstall "${NVM_TEST_VERSION}" || echo 'not installed'
# Exercise nvm's entire source-install pipeline - cache, extract, configure,
# make, make install, activation - against a tiny fake source tree, seeded
# into the download cache and installed with --offline. This runs everywhere,
# including on toolchains where real io.js can not compile; `install from
# source` covers the real compile, in CI's gcc:4.9 container job.
SLUG="$(nvm_get_download_slug iojs source "${NVM_TEST_VERSION}")"
COMPRESSION="$(nvm_get_artifact_compression "${NVM_TEST_VERSION}")"
CACHE_DIR="$(nvm_cache_dir)/src/${SLUG}"
STAGING="$(mktemp -d)"
mkdir -p "${STAGING}/${SLUG}" "${CACHE_DIR}"
cp ../fixtures/fake-source-tarball/configure ../fixtures/fake-source-tarball/Makefile "${STAGING}/${SLUG}/"
chmod +x "${STAGING}/${SLUG}/configure"
echo "${NVM_TEST_VERSION}" > "${STAGING}/${SLUG}/VERSION"
if [ "${COMPRESSION}" = 'tar.xz' ]; then
(cd "${STAGING}" && tar -cJf "${CACHE_DIR}/${SLUG}.${COMPRESSION}" "${SLUG}")
else
(cd "${STAGING}" && tar -czf "${CACHE_DIR}/${SLUG}.${COMPRESSION}" "${SLUG}")
fi
rm -rf "${STAGING}"
# Install from source
nvm install -s --offline "${NVM_PREFIXED_TEST_VERSION}" || die "'nvm install -s --offline ${NVM_PREFIXED_TEST_VERSION}' failed"
# Check
nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version not installed'
nvm run --silent "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" || die "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed"
rm -rf "${CACHE_DIR}"
+18 -1
View File
@@ -8,6 +8,23 @@ die () { echo "$@" ; exit 1; }
set -ex set -ex
# Compiling io.js requires a period toolchain: python 2 (its `configure`),
# and gcc <= 5 (its bundled V8). CI compiles it for real in a gcc:4.9
# container job; on modern toolchains, this can only be skipped
# (`install from fake source` covers nvm's source pipeline everywhere).
GCC_MAJOR="$(gcc -dumpversion 2>/dev/null | command cut -d. -f1)"
if ! command -v python2 >/dev/null 2>&1 && ! python -V 2>&1 | command grep -q '^Python 2'; then
echo 'python 2 is not available; skipping the io.js source install'
exit 0
fi
case "${GCC_MAJOR}" in
'' | *[!0-9]*) echo 'gcc is not available; skipping the io.js source install'; exit 0 ;;
esac
if [ "${GCC_MAJOR}" -gt 5 ]; then
echo "gcc <= 5 is required to compile io.js, got ${GCC_MAJOR}; skipping the io.js source install"
exit 0
fi
NVM_TEST_VERSION='v3.3.1' NVM_TEST_VERSION='v3.3.1'
NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}" NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}"
@@ -19,4 +36,4 @@ nvm uninstall "${NVM_TEST_VERSION}" || echo 'not installed'
# Check # Check
nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version not installed' nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version not installed'
nvm run "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" || "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed" nvm run --silent "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" || die "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed"
@@ -0,0 +1,45 @@
#!/bin/sh
die () { echo "$@" ; exit 1; }
\. ../../nvm.sh
set -ex
NVM_TEST_VERSION='v3.99.8'
NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}"
# Remove the stuff we're clobbering.
nvm uninstall "${NVM_TEST_VERSION}" || echo 'not installed'
# Exercise nvm's source-install pipeline against a tiny fake source tree,
# seeded into the download cache and installed with --offline (see `install
# from fake source`). This runs everywhere, including on toolchains where
# real io.js can not compile; `install version specified in .nvmrc from
# source` covers the real compile, in CI's gcc:4.9 container job.
SLUG="$(nvm_get_download_slug iojs source "${NVM_TEST_VERSION}")"
COMPRESSION="$(nvm_get_artifact_compression "${NVM_TEST_VERSION}")"
CACHE_DIR="$(nvm_cache_dir)/src/${SLUG}"
STAGING="$(mktemp -d)"
mkdir -p "${STAGING}/${SLUG}" "${CACHE_DIR}"
cp ../fixtures/fake-source-tarball/configure ../fixtures/fake-source-tarball/Makefile "${STAGING}/${SLUG}/"
chmod +x "${STAGING}/${SLUG}/configure"
echo "${NVM_TEST_VERSION}" > "${STAGING}/${SLUG}/VERSION"
if [ "${COMPRESSION}" = 'tar.xz' ]; then
(cd "${STAGING}" && tar -cJf "${CACHE_DIR}/${SLUG}.${COMPRESSION}" "${SLUG}")
else
(cd "${STAGING}" && tar -czf "${CACHE_DIR}/${SLUG}.${COMPRESSION}" "${SLUG}")
fi
rm -rf "${STAGING}"
# Install from source, with the version specified in .nvmrc
echo "${NVM_PREFIXED_TEST_VERSION}" > .nvmrc
nvm install -s --offline || die "'nvm install -s --offline' failed"
# Check
nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version is not installed'
nvm run --silent "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" \
|| die "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed"
rm -rf "${CACHE_DIR}"
+21 -3
View File
@@ -6,18 +6,36 @@ die () { echo "$@" ; exit 1; }
set -ex set -ex
# Compiling io.js requires a period toolchain: python 2 (its `configure`),
# and gcc <= 5 (its bundled V8). CI compiles it for real in a gcc:4.9
# container job; on modern toolchains, this can only be skipped
# (`install version specified in .nvmrc from fake source` covers nvm's
# source pipeline everywhere).
GCC_MAJOR="$(gcc -dumpversion 2>/dev/null | command cut -d. -f1)"
if ! command -v python2 >/dev/null 2>&1 && ! python -V 2>&1 | command grep -q '^Python 2'; then
echo 'python 2 is not available; skipping the io.js source install'
exit 0
fi
case "${GCC_MAJOR}" in
'' | *[!0-9]*) echo 'gcc is not available; skipping the io.js source install'; exit 0 ;;
esac
if [ "${GCC_MAJOR}" -gt 5 ]; then
echo "gcc <= 5 is required to compile io.js, got ${GCC_MAJOR}; skipping the io.js source install"
exit 0
fi
NVM_TEST_VERSION='v3.3.0' NVM_TEST_VERSION='v3.3.0'
NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}" NVM_PREFIXED_TEST_VERSION="iojs-${NVM_TEST_VERSION}"
# Remove the stuff we're clobbering. # Remove the stuff we're clobbering.
nvm uninstall "${NVM_TEST_VERSION}" || echo 'not installed' nvm uninstall "${NVM_TEST_VERSION}" || echo 'not installed'
# Install from binary # Install from source, with the version specified in .nvmrc
echo "${NVM_PREFIXED_TEST_VERSION}" > .nvmrc echo "${NVM_PREFIXED_TEST_VERSION}" > .nvmrc
nvm install -s || "'nvm install -s' failed" nvm install -s || die "'nvm install -s' failed"
# Check # Check
nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version is not installed' nvm_is_version_installed "${NVM_PREFIXED_TEST_VERSION}" || die 'version is not installed'
nvm run "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" \ nvm run --silent "${NVM_PREFIXED_TEST_VERSION}" --version | grep "${NVM_TEST_VERSION}" \
|| die "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed" || die "'nvm run ${NVM_PREFIXED_TEST_VERSION} --version | grep ${NVM_TEST_VERSION}' failed"
+2
View File
@@ -6,6 +6,8 @@ nvm uninstall iojs-v1.0.0
nvm uninstall iojs-v1.0.3 nvm uninstall iojs-v1.0.3
nvm uninstall iojs-v3.3.0 nvm uninstall iojs-v3.3.0
nvm uninstall iojs-v3.3.1 nvm uninstall iojs-v3.3.1
nvm uninstall iojs-v3.99.8
nvm uninstall iojs-v3.99.9
if [ -f ".nvmrc" ]; then if [ -f ".nvmrc" ]; then
rm .nvmrc rm .nvmrc
@@ -1,6 +1,27 @@
#!/bin/sh #!/bin/sh
die () { echo "$@" ; exit 1; } # State touched by the regression section below; cleanup restores it even on failure.
DEFAULT_PACKAGES_FILE="${NVM_DIR}/default-packages"
DEFAULT_PACKAGES_BACKUP=""
DEFAULT_PACKAGES_WROTE=""
TEST_ALIAS=""
cleanup () {
if [ -n "${DEFAULT_PACKAGES_WROTE}" ]; then
rm -f "${DEFAULT_PACKAGES_FILE}"
DEFAULT_PACKAGES_WROTE=""
fi
if [ -n "${DEFAULT_PACKAGES_BACKUP}" ] && [ -f "${DEFAULT_PACKAGES_BACKUP}" ]; then
mv "${DEFAULT_PACKAGES_BACKUP}" "${DEFAULT_PACKAGES_FILE}"
DEFAULT_PACKAGES_BACKUP=""
fi
if [ -n "${TEST_ALIAS}" ]; then
nvm unalias "${TEST_ALIAS}" > /dev/null 2>&1 || true
TEST_ALIAS=""
fi
}
die () { echo "$@" ; cleanup ; exit 1; }
\. ../../nvm.sh \. ../../nvm.sh
@@ -44,3 +65,54 @@ nvm use --lts=argon
node --version | grep v4.9.1 > /dev/null || die "nvm ls --lts=argon didn't use v4.9.1" node --version | grep v4.9.1 > /dev/null || die "nvm ls --lts=argon didn't use v4.9.1"
npm list --global | grep object-is > /dev/null || die "object-is isn't installed" npm list --global | grep object-is > /dev/null || die "object-is isn't installed"
# Regression: `--reinstall-packages-from` must still migrate packages when the
# target version is *already installed*. See https://github.com/nvm-sh/nvm/issues/3858
# install a fresh global package on the source (v9.7.0) only
nvm use 9.7.0
npm install -g is-nan@1.0.1 || die "npm install -g is-nan failed"
npm list --global --depth=0 | grep is-nan > /dev/null || die "is-nan isn't installed on v9.7.0"
# precondition: the already-installed target (v9.10.0) must not have it yet
nvm use 9.10.0
npm list --global --depth=0 | grep is-nan > /dev/null && die "is-nan should not be installed on v9.10.0 before reinstall"
# target is already installed, so this should report so AND still migrate packages
OUTPUT="$(nvm install --reinstall-packages-from=9.7.0 9.10.0 2>&1)" || die "nvm install --reinstall-packages-from=9.7.0 9.10.0 failed: ${OUTPUT}"
nvm_echo "${OUTPUT}" | grep "is already installed" > /dev/null || die "expected 'already installed' message, got: ${OUTPUT}"
nvm use 9.10.0
npm list --global --depth=0 | grep is-nan > /dev/null || die "is-nan was not migrated to already-installed v9.10.0"
# ...the same is true for default packages: they must install on the already-installed path too.
# back up any real default-packages file, then point it at a package the target lacks
if [ -f "${DEFAULT_PACKAGES_FILE}" ]; then
DEFAULT_PACKAGES_BACKUP="${DEFAULT_PACKAGES_FILE}.3858.bak"
mv "${DEFAULT_PACKAGES_FILE}" "${DEFAULT_PACKAGES_BACKUP}" || die "could not back up ${DEFAULT_PACKAGES_FILE}"
fi
DEFAULT_PACKAGES_WROTE=1
nvm_echo 'object-inspect@1.0.2' > "${DEFAULT_PACKAGES_FILE}"
# precondition: the already-installed target must not have the default package yet
nvm use 9.10.0
npm list --global --depth=0 | grep object-inspect > /dev/null && die "object-inspect should not be installed on v9.10.0 before default-packages test"
nvm install 9.10.0 > /dev/null 2>&1 || die "nvm install 9.10.0 (already installed, default-packages) failed"
nvm use 9.10.0
npm list --global --depth=0 | grep object-inspect > /dev/null || die "default packages were not installed on already-installed v9.10.0"
# restore the default-packages file before the next assertion
cleanup
# ...and `--alias` must be set on the already-installed path too.
TEST_ALIAS='nvm-3858-already-installed'
nvm unalias "${TEST_ALIAS}" > /dev/null 2>&1 || true # ensure a clean precondition
nvm install --alias="${TEST_ALIAS}" 9.10.0 > /dev/null 2>&1 || die "nvm install --alias=${TEST_ALIAS} 9.10.0 (already installed) failed"
TERM=dumb nvm alias "${TEST_ALIAS}" | grep 'v9.10.0' > /dev/null || die "--alias was not set on already-installed v9.10.0"
cleanup
+5
View File
@@ -0,0 +1,5 @@
if [ "_$1" = "_-m" ]; then
echo "loongarch64"
else
echo "Linux foo 6.12.54-16k #0 SMP PREEMPT_DYNAMIC Fri Dec 5 12:35:43 UTC loongarch64 GNU/Linux"
fi
+3 -1
View File
@@ -6,4 +6,6 @@ die () { echo "$@" ; exit 1; }
nvm use 0.10 nvm use 0.10
nvm exec stable -- node --help | grep 'Usage: node [options]' || die "Help menu should have been displayed for node and not nvm" # note: in a BRE, `[options]` is a bracket expression, so the literal `[options]`
# in node's help output could never match; match the unbracketed prefix instead
nvm exec stable -- node --help | grep 'Usage: node' || die "Help menu should have been displayed for node and not nvm"
@@ -1,30 +1,51 @@
#!/bin/sh #!/bin/sh
die () { echo "$@" ; exit 1; } die () { echo "$@" ; cleanup ; exit 1; }
# Source nvm # Source nvm
\. ../../../nvm.sh \. ../../../nvm.sh
# Version to install/uninstall \. ../../common.sh
NVM_TEST_VERSION=5.10.1
# Make sure it's not already here NVM_TEST_VERSION=v5.99.99
[ -e ../../../$NVM_TEST_VERSION ] && rm -R ../../../$NVM_TEST_VERSION
# Install it cleanup() {
nvm install $NVM_TEST_VERSION VERSION_PATH="${VERSION_PATH-}"
if [ -n "${VERSION_PATH}" ] && [ -d "${VERSION_PATH}" ]; then
sudo -n rm -f "${VERSION_PATH}/lib/root-owned-file" 2>/dev/null
rm -rf "${VERSION_PATH}"
fi
}
# Make sure it installed # The permissions check only trips on files that are neither writable nor
nvm ls | grep "$NVM_TEST_VERSION" || die "Failed to install node" # self-owned, and creating one requires another user: skip where passwordless
# sudo is unavailable; CI always has it.
if ! sudo -n true 2>/dev/null; then
echo 'passwordless sudo is not available, skipping'
exit 0
fi
# Install global module as root # Install a fake version to uninstall
npm_path=$(which npm) make_fake_node "${NVM_TEST_VERSION}" || die 'unable to make fake node'
sudo -n "$npm_path" install jspm@'<2' -g || die 'either sudo failed, or `npm install jspm -g` failed`' VERSION_PATH="$(nvm_version_path "${NVM_TEST_VERSION}")"
# Switch to another version so we can uninstall # Make part of the installation folder unwritable, and not self-owned
nvm use 0.12.7 mkdir -p "${VERSION_PATH}/lib"
sudo -n touch "${VERSION_PATH}/lib/root-owned-file" || die 'sudo touch failed'
sudo -n chmod 444 "${VERSION_PATH}/lib/root-owned-file" || die 'sudo chmod failed'
# Make sure the version to uninstall is not the active one
nvm deactivate >/dev/null 2>&1 || true
# Attempt to uninstall it # Attempt to uninstall it
RETURN_MESSAGE="$(nvm uninstall $NVM_TEST_VERSION 2>&1)" RETURN_MESSAGE="$(nvm uninstall "${NVM_TEST_VERSION}" 2>&1)"
CHECK_FOR="Cannot uninstall, incorrect permissions on installation folder" CHECK_FOR="Cannot uninstall, incorrect permissions on installation folder"
test "${RETURN_MESSAGE#*$CHECK_FOR}" != "$RETURN_MESSAGE" || die "Failed to show error message" case "${RETURN_MESSAGE}" in
*"${CHECK_FOR}"*) ;;
*) die "Failed to show error message; got: ${RETURN_MESSAGE}" ;;
esac
# ... and the version must not have been removed
nvm_is_version_installed "${NVM_TEST_VERSION}" || die 'version was uninstalled despite the permissions error'
cleanup
+42 -26
View File
@@ -2,37 +2,46 @@
die () { echo "$@" ; cleanup ; exit 1; } die () { echo "$@" ; cleanup ; exit 1; }
WORK="$PWD/nvm_get_latest-work.$$"
TEST_BIN="$WORK/bin"
cleanup() { cleanup() {
unset -f curl wget nvm_has unset -f curl wget
rm -rf "$WORK"
export PATH="$OLDPATH"
} }
\. ../../../nvm.sh \. ../../../nvm.sh
\. ../../common.sh
OLDPATH="$PATH"
EXPECTED_VERSION="v12.3.456" EXPECTED_VERSION="v12.3.456"
URL="https://github.com/nvm-sh/nvm/releases/tag/$EXPECTED_VERSION" URL="https://github.com/nvm-sh/nvm/releases/tag/$EXPECTED_VERSION"
EXPECTED_CURL_ARGS="--compressed -q -w %{url_effective}\n -L -s -S https://latest.nvm.sh -o /dev/null" EXPECTED_CURL_ARGS="--compressed -q -w %{url_effective}\n -L -s -S https://latest.nvm.sh -o /dev/null"
EXPECTED_WGET_ARGS="-q https://latest.nvm.sh --server-response -O /dev/null" EXPECTED_WGET_ARGS="-q https://latest.nvm.sh --server-response -O /dev/null"
export URL EXPECTED_CURL_ARGS EXPECTED_WGET_ARGS
curl() { VERSION_MESSAGE="
if [ $# -eq 1 ] && [ "$1" = "-V" ]; then
echo "
curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3 curl 7.47.0 (x86_64-pc-linux-gnu) libcurl/7.47.0 GnuTLS/3.4.10 zlib/1.2.8 libidn/1.32 librtmp/2.3
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp
Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets" Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP UnixSockets"
elif [ "_$*" != "_$EXPECTED_CURL_ARGS" ]; then
echo >&2 "expected args ($EXPECTED_CURL_ARGS), got ($*)" # fake curl/wget: `command curl` bypasses shell functions, so the mocks must be executables on PATH
return 1 make_fake_curl "$TEST_BIN" 'if [ "_$*" != "_$EXPECTED_CURL_ARGS" ]; then
else echo >&2 "expected args ($EXPECTED_CURL_ARGS), got ($*)"
echo $URL exit 1
fi fi
} echo "$URL"'
wget() {
if [ "_$*" != "_$EXPECTED_WGET_ARGS" ]; then cat > "$TEST_BIN/wget" <<'OUTER'
echo >&2 "expected args ($EXPECTED_WGET_ARGS), got ($*)" #!/bin/sh
return 1 if [ "_$*" != "_$EXPECTED_WGET_ARGS" ]; then
else echo >&2 "expected args ($EXPECTED_WGET_ARGS), got ($*)"
local WGET_CONTENTS exit 1
WGET_CONTENTS=" fi
cat >&2 <<CONTENTS
HTTP/1.1 301 Moved Permanently HTTP/1.1 301 Moved Permanently
Location: https://github.com/nvm-sh/nvm/releases/latest Location: https://github.com/nvm-sh/nvm/releases/latest
Content-Type: text/html; charset=utf-8 Content-Type: text/html; charset=utf-8
@@ -82,15 +91,22 @@ wget() {
X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff
Vary: Accept-Encoding Vary: Accept-Encoding
X-Served-By: 926b734ea1992f8ee1f88ab967a93dac X-Served-By: 926b734ea1992f8ee1f88ab967a93dac
" CONTENTS
"$WGET_CONTENTS" | while read line OUTER
do chmod +x "$TEST_BIN/wget"
>&2 echo "$line"
done
fi
}
\. ../../common.sh export PATH="$TEST_BIN:$OLDPATH"
# shadowing shell functions, like aliases baked into a user's shell, must be
# bypassed in favor of the executables on PATH (https://github.com/nvm-sh/nvm/issues/2923)
curl() {
echo >&2 'the shadowing curl function was called'
return 1
}
wget() {
echo >&2 'the shadowing wget function was called'
return 1
}
try nvm_get_latest try nvm_get_latest
[ "_$CAPTURED_STDOUT" = "_$EXPECTED_VERSION" ] \ [ "_$CAPTURED_STDOUT" = "_$EXPECTED_VERSION" ] \
@@ -2,20 +2,26 @@
die () { echo "$@" ; cleanup ; exit 1; } die () { echo "$@" ; cleanup ; exit 1; }
WORK="$PWD/nvm_get_latest_failed_redirect-work.$$"
TEST_BIN="$WORK/bin"
cleanup() { cleanup() {
unset -f curl wget rm -rf "$WORK"
export PATH="$OLDPATH"
} }
\. ../../../nvm.sh \. ../../../nvm.sh
\. ../../common.sh \. ../../common.sh
curl() { OLDPATH="$PATH"
return 1
} # fake curl/wget: `command curl` bypasses shell functions, so the mocks must be executables on PATH
wget() { make_fake_curl "$TEST_BIN" 'exit 1'
return 1 printf '#!/bin/sh\nexit 1\n' > "$TEST_BIN/wget"
} chmod +x "$TEST_BIN/wget"
export PATH="$TEST_BIN:$OLDPATH"
try_err nvm_get_latest try_err nvm_get_latest
[ "_$CAPTURED_STDERR" = "_https://latest.nvm.sh did not redirect to the latest release on GitHub" ] \ [ "_$CAPTURED_STDERR" = "_https://latest.nvm.sh did not redirect to the latest release on GitHub" ] \