From 4c3edc5e56518fafde75c874121c09383d1ac500 Mon Sep 17 00:00:00 2001 From: Jordan Harband Date: Mon, 26 Jan 2026 23:32:01 -0800 Subject: [PATCH] [actions] migrate Travis CI tests to GitHub Actions --- .github/workflows/tests-fast.yml | 101 +++++++++++++++ .github/workflows/tests-installation-iojs.yml | 99 ++++++++++++++ .github/workflows/tests-installation-node.yml | 122 ++++++++++++++++++ .github/workflows/tests-xenial.yml | 112 ++++++++++++++++ .travis.yml | 94 -------------- README.md | 4 +- test/fast/Unit tests/nvm_stdout_is_terminal | 2 +- .../install from binary with binary flag set | 7 + 8 files changed, 444 insertions(+), 97 deletions(-) create mode 100644 .github/workflows/tests-fast.yml create mode 100644 .github/workflows/tests-installation-iojs.yml create mode 100644 .github/workflows/tests-installation-node.yml create mode 100644 .github/workflows/tests-xenial.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/tests-fast.yml b/.github/workflows/tests-fast.yml new file mode 100644 index 0000000..af4ee21 --- /dev/null +++ b/.github/workflows/tests-fast.yml @@ -0,0 +1,101 @@ +name: 'Tests: fast' + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + fast: + permissions: + contents: read + + name: 'fast (${{ matrix.shell }}, ${{ matrix.awk }})' + runs-on: ubuntu-latest + defaults: + run: + shell: 'script -q -e -c "${{ matrix.shell }} {0}"' + + strategy: + fail-fast: false + matrix: + shell: + - sh + - bash + - dash + - zsh + # - ksh + awk: + - gawk + - mawk + + 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 + azure.archive.ubuntu.com:80 + packages.microsoft.com:443 + registry-1.docker.io:443 + auth.docker.io:443 + production.cloudflare.docker.com:443 + - uses: actions/checkout@v6 + with: + submodules: true + - name: Install zsh, additional shells, and awk variant + run: | + sudo apt-get update + sudo apt-get install -y zsh ${{ matrix.awk }} + if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then + sudo apt-get install -y ${{ matrix.shell }} + fi + # Set the selected awk as the default + sudo update-alternatives --set awk /usr/bin/${{ matrix.awk }} + shell: bash + - run: sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }} + - run: awk --version 2>&1 | head -1 || awk -W version 2>&1 | head -1 + - run: curl --version + - run: wget --version + - uses: ljharb/actions/node/install@main + name: 'npm install && version checks' + with: + node-version: 'lts/*' + skip-ls-check: true + - run: npm ls urchin + - run: npx which urchin + - run: env + - name: Hide system node + run: | + if [ -f /usr/local/bin/node ]; then sudo mv /usr/local/bin/node /usr/local/bin/node.bak; fi + if [ -f /usr/local/bin/npm ]; then sudo mv /usr/local/bin/npm /usr/local/bin/npm.bak; fi + if [ -f /usr/local/bin/npx ]; then sudo mv /usr/local/bin/npx /usr/local/bin/npx.bak; fi + shell: bash + - name: Run fast tests + run: | + URCHIN_PATH="$(npx which urchin)" + unset NVM_CD_FLAGS NVM_BIN NVM_INC + export NVM_DIR="${{ github.workspace }}" + export PATH="$(echo "$PATH" | tr ':' '\n' | grep -v '\.nvm' | grep -v 'toolcache' | tr '\n' ':')" + make TERM=xterm-256color TEST_SUITE="fast" SHELL="${{ matrix.shell }}" URCHIN="$URCHIN_PATH" test-${{ matrix.shell }} + - name: Restore system node + if: always() + run: | + if [ -f /usr/local/bin/node.bak ]; then sudo mv /usr/local/bin/node.bak /usr/local/bin/node; fi + if [ -f /usr/local/bin/npm.bak ]; then sudo mv /usr/local/bin/npm.bak /usr/local/bin/npm; fi + if [ -f /usr/local/bin/npx.bak ]; then sudo mv /usr/local/bin/npx.bak /usr/local/bin/npx; fi + shell: bash + + all: + permissions: + contents: none + name: 'all fast tests' + needs: [fast] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.github/workflows/tests-installation-iojs.yml b/.github/workflows/tests-installation-iojs.yml new file mode 100644 index 0000000..3d0c37e --- /dev/null +++ b/.github/workflows/tests-installation-iojs.yml @@ -0,0 +1,99 @@ +name: 'Tests: installation_iojs' + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + installation_iojs_without_curl: + permissions: + contents: read + + name: 'installation_iojs without curl (${{ matrix.shell }})' + runs-on: ubuntu-latest + defaults: + run: + shell: 'script -q -e -c "${{ matrix.shell }} {0}"' + + strategy: + fail-fast: false + matrix: + shell: + - sh + - bash + - dash + - zsh + # - ksh + + 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 + azure.archive.ubuntu.com:80 + packages.microsoft.com:443 + - uses: actions/checkout@v6 + with: + submodules: true + - name: Install zsh and additional shells + run: | + sudo apt-get update + sudo apt-get install -y zsh + if [ "${{ matrix.shell }}" != "sh" ] && [ "${{ matrix.shell }}" != "bash" ] && [ "${{ matrix.shell }}" != "zsh" ]; then + sudo apt-get install -y ${{ matrix.shell }} + fi + shell: bash + - run: sudo ${{ matrix.shell }} --version 2> /dev/null || dpkg -s ${{ matrix.shell }} 2> /dev/null || which ${{ matrix.shell }} + - run: wget --version + - uses: ljharb/actions/node/install@main + name: 'npm install && version checks' + with: + node-version: 'lts/*' + skip-ls-check: true + - run: npm ls urchin + - run: npx which urchin + - name: Remove curl + run: sudo apt-get remove curl -y + shell: bash + - run: '! command -v curl' + shell: bash + - run: env + - name: Hide system node + run: | + if [ -f /usr/local/bin/node ]; then sudo mv /usr/local/bin/node /usr/local/bin/node.bak; fi + if [ -f /usr/local/bin/npm ]; then sudo mv /usr/local/bin/npm /usr/local/bin/npm.bak; fi + if [ -f /usr/local/bin/npx ]; then sudo mv /usr/local/bin/npx /usr/local/bin/npx.bak; fi + shell: bash + - name: Run installation_iojs tests + run: | + URCHIN_PATH="$(npx which urchin)" + unset NVM_CD_FLAGS NVM_BIN NVM_INC + export NVM_DIR="${{ github.workspace }}" + export PATH="$(echo "$PATH" | tr ':' '\n' | grep -v '\.nvm' | grep -v 'toolcache' | tr '\n' ':')" + make TERM=xterm-256color TEST_SUITE="installation_iojs" SHELL="${{ matrix.shell }}" URCHIN="$URCHIN_PATH" test-${{ matrix.shell }} + - name: Restore system node + if: always() + run: | + if [ -f /usr/local/bin/node.bak ]; then sudo mv /usr/local/bin/node.bak /usr/local/bin/node; fi + if [ -f /usr/local/bin/npm.bak ]; then sudo mv /usr/local/bin/npm.bak /usr/local/bin/npm; fi + if [ -f /usr/local/bin/npx.bak ]; then sudo mv /usr/local/bin/npx.bak /usr/local/bin/npx; fi + shell: bash + - name: Restore curl + if: always() + run: sudo apt-get install curl -y + shell: bash + + all: + permissions: + contents: none + name: 'all installation_iojs tests' + needs: [installation_iojs_without_curl] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.github/workflows/tests-installation-node.yml b/.github/workflows/tests-installation-node.yml new file mode 100644 index 0000000..f288634 --- /dev/null +++ b/.github/workflows/tests-installation-node.yml @@ -0,0 +1,122 @@ +name: 'Tests: installation_node' + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + installation_node: + permissions: + contents: read + + name: "installation_node (${{ matrix.shell }}${{ matrix.without_curl && ', without curl' || '' }})" + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + shell: + - sh + - bash + - dash + - zsh + # - ksh + without_curl: + - false + - true + + 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 + azure.archive.ubuntu.com:80 + packages.microsoft.com:443 + archive.ubuntu.com:80 + security.ubuntu.com:80 + production.cloudflare.docker.com:443 + registry-1.docker.io:443 + auth.docker.io:443 + - uses: actions/checkout@v6 + with: + submodules: true + - uses: ljharb/actions/node/install@main + name: 'npm install && version checks' + with: + node-version: 'lts/*' + skip-ls-check: true + - run: npm ls urchin + - run: npx which urchin + - name: Run installation_node tests in container + run: | + docker run --rm \ + -v "${{ github.workspace }}:/workspace" \ + -w /workspace \ + -e "TEST_SHELL=${{ matrix.shell }}" \ + -e "TERM=xterm-256color" \ + -e "DEBIAN_FRONTEND=noninteractive" \ + -e "GITHUB_ACTIONS=true" \ + -e "WITHOUT_CURL=${{ matrix.without_curl }}" \ + ubuntu:16.04 \ + bash -c ' + set -ex + + # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors + # apt-get update can return 0 even with partial failures, so check for warnings + for i in 1 2 3 4 5; do + if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then + echo "apt-get update had warnings/errors, attempt $i/5" + cat /tmp/apt-update.log + sleep $((i * 5)) + else + break + fi + done + + apt-get install -y git curl wget make build-essential python zsh libssl-dev + if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then + apt-get install -y $TEST_SHELL || true + fi + + # Use nvm to install Node.js for running urchin + # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04) + export NVM_DIR="/workspace" + . /workspace/nvm.sh + nvm install 16 + nvm use 16 + + npm ls urchin + URCHIN_PATH="$(npx which urchin)" + + # Remove curl if testing without it + if [ "$WITHOUT_CURL" = "true" ]; then + apt-get remove curl -y + ! command -v curl + fi + + # Now clean up nvm state for the actual tests, but keep NVM_DIR set + nvm deactivate || true + nvm unalias default || true + unset NVM_CD_FLAGS NVM_BIN NVM_INC + export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")" + + # Clean any cached files from the nvm install above + rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias" + + make TEST_SUITE="installation_node" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL + ' + + all: + permissions: + contents: none + name: 'all installation_node tests' + needs: [installation_node] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.github/workflows/tests-xenial.yml b/.github/workflows/tests-xenial.yml new file mode 100644 index 0000000..474761f --- /dev/null +++ b/.github/workflows/tests-xenial.yml @@ -0,0 +1,112 @@ +name: 'Tests: xenial' + +on: [push, pull_request] + +permissions: + contents: read + +jobs: + xenial: + permissions: + contents: read + + name: 'xenial (${{ matrix.shell }})' + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + shell: + - sh + - bash + - dash + - zsh + # - ksh + + 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 + azure.archive.ubuntu.com:80 + packages.microsoft.com:443 + archive.ubuntu.com:80 + security.ubuntu.com:80 + production.cloudflare.docker.com:443 + registry-1.docker.io:443 + auth.docker.io:443 + - uses: actions/checkout@v6 + with: + submodules: true + - uses: ljharb/actions/node/install@main + name: 'npm install && version checks' + with: + node-version: 'lts/*' + skip-ls-check: true + - run: npm ls urchin + - run: npx which urchin + - name: Run xenial tests in container + run: | + docker run --rm \ + -v "${{ github.workspace }}:/workspace" \ + -w /workspace \ + -e "TEST_SHELL=${{ matrix.shell }}" \ + -e "TERM=xterm-256color" \ + -e "DEBIAN_FRONTEND=noninteractive" \ + -e "GITHUB_ACTIONS=true" \ + ubuntu:16.04 \ + bash -c ' + set -ex + + # Retry apt-get update up to 5 times due to flaky Ubuntu mirrors + # apt-get update can return 0 even with partial failures, so check for warnings + for i in 1 2 3 4 5; do + if apt-get update 2>&1 | tee /tmp/apt-update.log | grep -qE "^(W:|E:|Err:)"; then + echo "apt-get update had warnings/errors, attempt $i/5" + cat /tmp/apt-update.log + sleep $((i * 5)) + else + break + fi + done + + apt-get install -y git curl wget make build-essential python zsh libssl-dev + if [ "$TEST_SHELL" != "sh" ] && [ "$TEST_SHELL" != "bash" ]; then + apt-get install -y $TEST_SHELL || true + fi + + # Use nvm to install Node.js for running urchin + # Node 16 is the last version supporting GLIBC 2.23 (Ubuntu 16.04) + export NVM_DIR="/workspace" + . /workspace/nvm.sh + nvm install 16 + nvm use 16 + + npm ls urchin + URCHIN_PATH="$(npx which urchin)" + + # Now clean up nvm state for the actual tests, but keep NVM_DIR set + nvm deactivate || true + nvm unalias default || true + unset NVM_CD_FLAGS NVM_BIN NVM_INC + export PATH="$(echo "$PATH" | tr ":" "\n" | grep -v "\.nvm" | grep -v "toolcache" | tr "\n" ":")" + + # Clean any cached files from the nvm install above + rm -rf "$NVM_DIR/.cache" "$NVM_DIR/versions" "$NVM_DIR/alias" + + make TEST_SUITE="xenial" SHELL="$TEST_SHELL" URCHIN="$URCHIN_PATH" test-$TEST_SHELL + ' + + all: + permissions: + contents: none + name: 'all xenial tests' + needs: [xenial] + runs-on: ubuntu-latest + steps: + - run: true diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ed22ae1..0000000 --- a/.travis.yml +++ /dev/null @@ -1,94 +0,0 @@ -language: generic -dist: focal -addons: - apt: - packages: - - zsh - # - ksh - # - gcc-4.8 - # - g++-4.8 - -# https://gist.github.com/iedemam/9830045 -git: - submodules: false - -cache: - ccache: true - directories: - - $TRAVIS_BUILD_DIR/.cache - - $TRAVIS_BUILD_DIR/node_modules -before_install: - - sudo sed -i 's/mozilla\/DST_Root_CA_X3.crt/!mozilla\/DST_Root_CA_X3.crt/g' /etc/ca-certificates.conf - - sudo update-ca-certificates -f - - # https://gist.github.com/iedemam/9830045 - - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules - - git submodule update --init --recursive - - - $SHELL --version 2> /dev/null || dpkg -s $SHELL 2> /dev/null || which $SHELL - - curl --version - - wget --version - - bash --version | head - - zsh --version - - dpkg -s dash | grep ^Version | awk '{print $2}' - # install python - - pyenv local 2.7.18 || pyenv install 2.7.18 - - pyenv local 2.7.18 || echo 'pyenv failed' - - python -V -install: - - if [ -z "${SHELLCHECK-}" ]; then nvm install 16 && nvm unalias default && npm install && npm prune && npm ls urchin doctoc eclint dockerfile_lint; fi - - '[ -z "$WITHOUT_CURL" ] || sudo apt-get remove curl -y' -script: - - if [ -n "${SHELL-}" ] && [ -n "${TEST_SUITE}" ]; then if [ "${TEST_SUITE}" = 'installation_iojs' ] || [ "${TEST_SUITE}" = 'xenial' ]; then travis_retry make TEST_SUITE=$TEST_SUITE URCHIN="$(npm bin)/urchin" test-$SHELL ; else make TEST_SUITE=$TEST_SUITE URCHIN="$(npm bin)/urchin" test-$SHELL; fi; fi -before_cache: - - if [ -n "$WITHOUT_CURL" ]; then sudo apt-get install curl -y ; fi -jobs: - include: - - env: SHELL=bash TEST_SUITE=installation_node - dist: xenial - - env: SHELL=bash TEST_SUITE=installation_node WITHOUT_CURL=1 - dist: xenial - - env: SHELL=sh TEST_SUITE=installation_node - dist: xenial - - env: SHELL=sh TEST_SUITE=installation_node WITHOUT_CURL=1 - dist: xenial - - env: SHELL=dash TEST_SUITE=installation_node - dist: xenial - - env: SHELL=dash TEST_SUITE=installation_node WITHOUT_CURL=1 - dist: xenial - - env: SHELL=zsh TEST_SUITE=installation_node - dist: xenial - - env: SHELL=zsh TEST_SUITE=installation_node WITHOUT_CURL=1 - dist: xenial - #- env: SHELL=ksh TEST_SUITE=installation_node - # dist: xenial - #- env: SHELL=ksh TEST_SUITE=installation_node WITHOUT_CURL=1 - # dist: xenial - - env: SHELL=bash TEST_SUITE=xenial - dist: xenial - - env: SHELL=sh TEST_SUITE=xenial - dist: xenial - - env: SHELL=dash TEST_SUITE=xenial - dist: xenial - - env: SHELL=zsh TEST_SUITE=xenial - dist: xenial - #- env: SHELL=ksh TEST_SUITE=xenial - # dist: xenial -env: - global: - - CXX=g++ - - CC=gcc - - PATH="$(echo $PATH | sed 's/::/:/')" - - PATH="/usr/lib/ccache/:$PATH" - - NVM_DIR="${TRAVIS_BUILD_DIR}" - matrix: - - SHELL=sh TEST_SUITE=fast - - SHELL=dash TEST_SUITE=fast - - SHELL=bash TEST_SUITE=fast - - SHELL=zsh TEST_SUITE=fast - # - SHELL=ksh TEST_SUITE=fast - - SHELL=sh TEST_SUITE=installation_iojs WITHOUT_CURL=1 - - SHELL=dash TEST_SUITE=installation_iojs WITHOUT_CURL=1 - - SHELL=bash TEST_SUITE=installation_iojs WITHOUT_CURL=1 - - SHELL=zsh TEST_SUITE=installation_iojs WITHOUT_CURL=1 - # - SHELL=ksh TEST_SUITE=installation_iojs WITHOUT_CURL=1 diff --git a/README.md b/README.md index 4a189f3..1727d15 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ -# Node Version Manager [![Build Status](https://app.travis-ci.com/nvm-sh/nvm.svg?branch=master)][3] [![nvm version](https://img.shields.io/badge/version-v0.40.3-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.3-yellow.svg)][4] [![CII Best Practices](https://bestpractices.dev/projects/684/badge)](https://bestpractices.dev/projects/684) @@ -1038,7 +1038,7 @@ To change the user directory and/or account name follow the instructions [here]( [1]: https://github.com/nvm-sh/nvm.git [2]: https://github.com/nvm-sh/nvm/blob/v0.40.3/install.sh -[3]: https://app.travis-ci.com/nvm-sh/nvm +[3]: https://github.com/nvm-sh/nvm/actions/workflows/tests-fast.yml [4]: https://github.com/nvm-sh/nvm/releases/tag/v0.40.3 [Urchin]: https://git.sdf.org/tlevine/urchin [Fish]: https://fishshell.com diff --git a/test/fast/Unit tests/nvm_stdout_is_terminal b/test/fast/Unit tests/nvm_stdout_is_terminal index d6acb42..69d5649 100755 --- a/test/fast/Unit tests/nvm_stdout_is_terminal +++ b/test/fast/Unit tests/nvm_stdout_is_terminal @@ -25,7 +25,7 @@ fi ! nvm_stdout_is_terminal >"$tempfile" || die 'nvm_stdout_is_terminal should be false when stdout goes to a file' [ "$(nvm_stdout_is_terminal; echo $?)" = "1" ] || die 'nvm_stdout_is_terminal should be false in command substitution' -# also test the 'true' case while running on travis-ci or similar environments +# also test the 'true' case while running on CI or similar environments nvm_stdout_is_terminal >/dev/tty || die 'nvm_stdout_is_terminal should be true when stdout goes to /dev/tty' nvm_stdout_is_terminal >/dev/tty 2>/dev/null || die 'nvm_stdout_is_terminal should be true when stdout goes to /dev/tty and stderr is redirected' nvm_stdout_is_terminal >/dev/tty