Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Azure DevOps private agent - how to install node using nvm

I am trying to setup a private build agent for Azure DevOps on Ubuntu. And I need to use npm task for builds.

I tried to use nvm to install the latest node, and the installation was successful:

curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
nvm install 11.10.1

I can check node -v and npm -v. But when the npm task is executed from the pipeline - it fails with

Unable to locate executable file: 'npm'. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.

In my PATH I have /usr/local/nvm/versions/node/v11.10.1/bin and ls -l shows:

lrwxrwxrwx 1 500 500 38 Feb 28 06:00 /usr/local/nvm/versions/node/v11.10.1/bin/npm -> ../lib/node_modules/npm/bin/npm-cli.js

I also added 777 (just to try it!) for npm-cli.js, and still no luck.

I also found this similar question - https://github.com/Microsoft/azure-pipelines-agent/issues/1862

How to properly install node and npm using nvm on Ubuntu agent for Azure DevOps?

like image 456
JleruOHeP Avatar asked Sep 02 '25 16:09

JleruOHeP


2 Answers

To get this to work I ended up creating a bash script that proxies to nvm, and then tells the agent to update the PATH variable to the current NVM.

Create a file at /usr/local/bin/nvm containing this:

#!/usr/bin/env bash
# Store the current path so we can check to see if it changes
OLD_PATH=$PATH

# Normal NVM stuff
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm

# Execute NVM and pass all the arguments
nvm $@

# Check to see if the path has changed, and if an azure agent is running the
# command by checking the existence of the $AGENT_VERSION variable.
if [[ "$OLD_PATH" != "$PATH" && ! -z ${AGENT_VERSION+x} ]]; then
    # Grab the current node executable Something like:
    #  /Users/digitaldev/.nvm/versions/node/v10.16.3/bin
    CURRENT_NODE=$(nvm which current)
    # Resolve to directory of the node executable Something like
    # /Users/digitaldev/.nvm/versions/node/v10.16.3
    BIN_DIR=$(dirname "$CURRENT_NODE")
    # Tell Azure Pipeline to update the PATH [1]
    echo "##vso[task.prependpath]$BIN_DIR"
fi

Make the file executable:

chmod +x /usr/local/bin/nvm

Now when an Azure Pipeline runs nvm it'll update the path to look for the nvm version of node.

[1] Logging Commands PrependPath

like image 182
Kyle Avatar answered Sep 04 '25 19:09

Kyle


Just the nvm

I create a template like this based on the instructions from nvm.sh and set the NVM_DIR and PATH accordingly.

steps:
  - bash: |
      curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.36.0/install.sh | bash
      export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
      [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
      nvm install
      nvm use
      echo "##vso[task.setvariable variable=NVM_DIR;]$NVM_DIR"
      echo "##vso[task.setvariable variable=PATH;]$PATH"
    displayName: "Install Node.js"

I also add a .nvmrc as documented in nvm.sh so that the version of node to use is specified.

Then I use it in my pipeline as follows

steps:
  - template: templates/install-node-js.yml
  - bash: |
      node --version

With caching and node dependencies

This is my template for installing node and also doing caches to the packages in package-lock.json.

steps:
  - task: Cache@2
    inputs:
      key: 'nvm | "$(Agent.OS)" | .nvmrc'
      path: $(Pipeline.Workspace)/.nvm
    displayName: "Cache NVM"
  - task: Cache@2
    inputs:
      key: 'npm | "$(Agent.OS)" | package-lock.json'
      path: $(Build.SourcesDirectory)/node_modules
    displayName: "Cache node dependencies"
  - bash: |
      set -e
      if [ $(System.Debug) ]
      then
        set -x
      fi
      if [ ! -s $NVM_DIR/nvm.sh ]
      then
        mkdir -p $NVM_DIR
        curl -so- https://raw.githubusercontent.com/nvm-sh/nvm/v0.36.0/install.sh | bash
      fi
      . $NVM_DIR/nvm.sh || true
      nvm install
      nvm use
      npm ci
      echo "##vso[task.setvariable variable=PATH;]$PATH"
    env:
      NVM_DIR: $(Pipeline.Workspace)/.nvm
    displayName: Install Node and dependencies
like image 23
Archimedes Trajano Avatar answered Sep 04 '25 20:09

Archimedes Trajano