From d1904763457f1dc382b3b6526606bf872e15b7e2 Mon Sep 17 00:00:00 2001 From: Yashvardhan Thanvi Date: Wed, 4 Nov 2026 00:35:16 +0530 Subject: [PATCH] [Fix] `nvm install`: apply `--alias`, `--default` and `--save` after every install `nvm_install_binary` set the alias from its caller's variables, so a source install or an `$NVM_INSTALL_THIRD_PARTY_HOOK` install never got it, and no fresh install wrote `.nvmrc`. Apply both at the end of `nvm install`, after the install is validated. `--lts` without a version, or `lts/*`, leaves no provided version, and `nvm alias` treats an empty target as `nvm unalias`: `nvm install --lts --default` on an installed version removed the default alias. In that case point the alias at `lts/`, as the default alias already is. --- nvm.sh | 24 +++++- .../nvm install --alias, --default and --save | 80 +++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) create mode 100755 test/fast/Unit tests/nvm install --alias, --default and --save diff --git a/nvm.sh b/nvm.sh index d3c08085..d1e8b94c 100755 --- a/nvm.sh +++ b/nvm.sh @@ -3680,9 +3680,6 @@ nvm_install_binary() { fi if nvm_install_binary_extract "${NVM_OS}" "${PREFIXED_VERSION}" "${VERSION}" "${TARBALL}" "${TMPDIR}"; then - if [ -n "${ALIAS-}" ]; then - nvm alias "${ALIAS}" "${provided_version}" - fi return 0 fi @@ -5340,7 +5337,12 @@ nvm() { fi if [ $EXIT_CODE -eq 0 ] && [ -n "${ALIAS-}" ]; then - nvm alias "${ALIAS}" "${provided_version}" + # an LTS install may have no provided version, and an empty target would remove the alias + if [ -z "${provided_version}" ] && [ -n "${LTS-}" ]; then + nvm alias "${ALIAS}" "lts/${LTS}" + else + nvm alias "${ALIAS}" "${provided_version}" + fi EXIT_CODE=$? fi @@ -5453,6 +5455,20 @@ nvm() { fi fi + if [ $EXIT_CODE -eq 0 ] && [ $NVM_WRITE_TO_NVMRC -eq 1 ]; then + nvm_write_nvmrc "${VERSION}" + EXIT_CODE=$? + fi + + if [ $EXIT_CODE -eq 0 ] && [ -n "${ALIAS-}" ]; then + if [ -z "${provided_version}" ] && [ -n "${LTS-}" ]; then + nvm alias "${ALIAS}" "lts/${LTS}" + else + nvm alias "${ALIAS}" "${provided_version}" + fi + EXIT_CODE=$? + fi + return $EXIT_CODE ;; "uninstall") diff --git a/test/fast/Unit tests/nvm install --alias, --default and --save b/test/fast/Unit tests/nvm install --alias, --default and --save new file mode 100755 index 00000000..30e790ff --- /dev/null +++ b/test/fast/Unit tests/nvm install --alias, --default and --save @@ -0,0 +1,80 @@ +#!/bin/sh + +cleanup() { + [ -n "${NVM_DIR}" ] && [ -d "${NVM_DIR}" ] && rm -rf "${NVM_DIR}" + rm -f .nvmrc + if [ -f .nvmrc.orig ]; then mv .nvmrc.orig .nvmrc; fi + unset -f die cleanup reset nvm_remote_version nvm_has_executable nvm_binary_available \ + nvm_get_make_jobs nvm_install_binary nvm_install_source nvm_install_npm_if_needed \ + nvm_install_default_packages + unset NVM_DIR version OUTPUT +} + +die() { echo "$@" ; cleanup ; exit 1; } + +: nvm.sh +\. ../../../nvm.sh + +\. ../../common.sh + +unset npm_config_prefix NPM_CONFIG_PREFIX + +if [ -f .nvmrc ]; then mv .nvmrc .nvmrc.orig; fi + +NVM_DIR="$(mktemp -d)" +[ -n "${NVM_DIR}" ] || die 'unable to create temp NVM_DIR' +version='v20.0.0' + +# Stay offline: both install methods create a fake node. +nvm_remote_version() { nvm_echo "${version}"; } +nvm_has_executable() { return 0; } +nvm_binary_available() { return 0; } +nvm_get_make_jobs() { NVM_MAKE_JOBS=1; } +nvm_install_binary() { make_fake_node "${version}"; } +nvm_install_source() { make_fake_node "${version}"; } +nvm_install_npm_if_needed() { return 0; } +nvm_install_default_packages() { :; } + +reset() { + rm -rf "${NVM_DIR:?}/versions" "${NVM_DIR}/alias" .nvmrc +} + +reset +nvm install -s --alias=foo "${version}" > /dev/null 2>&1 || die "\`nvm install -s --alias=foo ${version}\` failed" +OUTPUT="$(nvm_alias foo)" +[ "${OUTPUT}" = "${version}" ] || die "expected the foo alias to be ${version} after a source install, got >${OUTPUT}<" + +reset +nvm install --alias=foo "${version}" > /dev/null 2>&1 || die "\`nvm install --alias=foo ${version}\` failed" +OUTPUT="$(nvm_alias foo)" +[ "${OUTPUT}" = "${version}" ] || die "expected the foo alias to be ${version} after a binary install, got >${OUTPUT}<" + +reset +nvm alias default v18.0.0 > /dev/null 2>&1 +nvm install -s --default "${version}" > /dev/null 2>&1 || die "\`nvm install -s --default ${version}\` failed" +OUTPUT="$(nvm_alias default)" +[ "${OUTPUT}" = "${version}" ] || die "expected the default alias to be ${version} after a source install, got >${OUTPUT}<" + +reset +nvm alias default v18.0.0 > /dev/null 2>&1 +nvm install -s --lts --default > /dev/null 2>&1 || die '`nvm install -s --lts --default` failed' +OUTPUT="$(nvm_alias default)" +[ "${OUTPUT}" = 'lts/*' ] || die "expected the default alias to be lts/* after an LTS install, got >${OUTPUT}<" + +# again, now that the version is installed +nvm install -s --lts --default > /dev/null 2>&1 || die '`nvm install -s --lts --default` failed for an installed version' +OUTPUT="$(nvm_alias default)" +[ "${OUTPUT}" = 'lts/*' ] || die "expected the default alias to stay lts/* for an installed version, got >${OUTPUT}<" + +# with `--lts` and an explicit version, the alias points at that version +reset +nvm install -s --lts --default "${version}" > /dev/null 2>&1 || die "\`nvm install -s --lts --default ${version}\` failed" +OUTPUT="$(nvm_alias default)" +[ "${OUTPUT}" = "${version}" ] || die "expected the default alias to be ${version} for \`--lts ${version}\`, got >${OUTPUT}<" + +reset +nvm install --save "${version}" > /dev/null 2>&1 || die "\`nvm install --save ${version}\` failed" +OUTPUT="$(cat .nvmrc 2> /dev/null)" +[ "${OUTPUT}" = "${version}" ] || die "expected \`nvm install --save ${version}\` to write .nvmrc, got >${OUTPUT}<" + +cleanup