SonarCloudAnalyze task fails with outdated node version despite using NodeJS Installer Tool prior

We are using Azure Pipelines in Azure Devops to build our project and are attempting to analyze the project with the SonarCloudAnalyze@1 task.

The task works as expected for my .NET/C# project, but not my Angular/TypeScript project. I believe this is due to the fact that the Analyzer detects Javascript, and requires NodeJS for the analysis.

The error I’m receiving when running my pipeline which targets my Angular/TypeScript project is as follows:

The version of node.js (10) you have used to run this analysis is deprecated and we stopped accepting it.
Please update to at least node.js 14. You can find more information here: https://docs.sonarcloud.io/appendices/scanner-environment/

Our Angular project has a requirement of NodeJS 10 due to the version of Angular (7) we still run. I understand, according to the documentation, that the SonarScanner should be able to use a different version for the analysis.

Running NodeJS Tool Installer task (NodeTool@1) with versionSpec 16.x
I have attempted to configure it to use a different version first by running the task NodeTool@1 with versionSpec: ‘16.x’ prior to the SonarCloudAnalyze@1 task. This downloads the appropriate node version and puts it in the agent’s tools directory. Further, the task says it is prepending the path to the environement PATH variable. I have confirmed it is doing so by executing a task with a simple echo statement.

  - task: NodeTool@0
    displayName: "Install Node 16.x"
    inputs:
      versionSpec: "16.x"

  - task: CmdLine@2
    inputs:
      script: "echo %PATH%"

This outputs the PATH variable with the correct path to version 16.15.1 prepended to the front.

I then run the SonarCloudAnalyze@1 where it fails stating that it is still trying to use node version 10.

At this point, I notice that node version 10 is installed on the agent machine. However, my expectation is that SonarScanner should be using the node version referenced by the PATH environment variable.

Running SonarCloudPrepare@1 after NodeTool@0 with versionSpec 16.x
I decided that maybe the preparation stage needed to also be run with version 16 tool set on the PATH. So, I run the preparation task after the node tool installer task. Then, when I get ready to build, I run the node tool installer task again to switch back to version 10.x which is required by my project. Finally, when I get ready to analyze, I once again run the node tool installer task to switch back to version 16.

It still fails with the same error stating that the analyzer is trying to use node version 10.

Setting the path to the node version explicitly in sonar-project.properties
I tried setting the sonar-project.properties to explicitly point at the nodejs executable to use. I did this as follows:

sonar.nodejs.executable=../../_tool/node/16.15.1/x64/node.exe

While this does appear to work, it has the disadvantage of self-hosted agents needing to be configured in a specific way so that we can make assumptions about where the executable would be located.

I tried to embed some variables in the file, but they did not seem to get expanded. For example:

sonar.nodejs.executable=$(Agent.ToolsDirectory)/node/16.15.1/x64/node.exe

But the scanner was unable to find the location (probably due to it not getting expanded).

ERROR: Provided Node.js executable file does not exist. Property 'sonar.nodejs.executable' was set to '$(Agent.ToolsDirectory)/node/16.15.1/x64/node.exe'

Another disadvantage of using a hardcoded path to the executable like this would be that we would manually need to update the version of Node being used with the analyzer over time instead of just allowing the tool installer task to always use the latest.

Here is my complete Azure Pipeline YAML, with potentially sensitive information asterisked out.

trigger:
  - master

pool:
  name: "Default"

steps:
  - task: NodeTool@0
    displayName: "Configure Node 16.x"
    inputs:
      versionSpec: "16.x"

  - task: SonarCloudPrepare@1
    displayName: "Prepare SonarCloud Analysis"
    inputs:
      SonarCloud: "SonarCloud"
      organization: "***"
      projectKey: "***"
      projectName: "***"
      scannerMode: "CLI"
      configMode: "file"
      configFile: "web/sonar-project.properties"

  - task: NodeTool@0
    displayName: "Configure Node 10.x"
    inputs:
      versionSpec: "10.x"

  - task: Npm@1
    displayName: "Install NPM Dependencies"
    inputs:
      command: "install"
      workingDir: "web/"

  - task: Npm@1
    displayName: "Build Angular"
    inputs:
      command: "custom"
      workingDir: "web/"
      customCommand: "run build -- --c=production"

  - task: NodeTool@0
    displayName: "Configure Node 16.x"
    inputs:
      versionSpec: "16.x"

  - task: SonarCloudAnalyze@1
    displayName: "SonarCloud Analysis"

  - task: SonarCloudPublish@1
    inputs:
      pollingTimeoutSec: "300"

I’m looking for a solution that doesn’t involve hardcoded paths to the Node installation. Does anyone have an idea why the analyzer doesn’t seem to be honoring the PATH variable’s path to the node installation?

Hi Chris,

First of all, thank you for this very detailed analysis!
Let me give you some insight into the logic to retrieve the node used by the analyser on Windows OS.

First, we check if sonar.nodejs.executable is provided.
If no, we then check if one of this PATH exists: "C:\\Program Files\\nodejs\\bin\\node.exe" or "C:\\Program Files\\nodejs\\node.exe"
If none exist, we use the where command to find node.

Currently, we are not looking at the system PATH to find node. This is something to be improved, I will create a ticket to tackle it.

May I ask you to check if "C:\\Program Files\\nodejs\\bin\\node.exe" or "C:\\Program Files\\nodejs\\node.exe" exist and to which version of node they point? If they don’t exist, which node version is retrieved by the were command?

Based on the provided logic, you can now adjust your settings so that the analyser will retrieve node 16.

I hope that helps and let me know if you need further assistance.

Thank you for the reply and detailed information. I’m understanding from your reply that Sonar does not check the actual PATH environment variable, but rather uses the WHERE command.

My WHERE command returns “C:\Program Files\nodejs\node.exe” which is version 10.24.1. We have this outdated version of Node.js installed to facilitate Angular 7 compilation, the version we are still using in production at this time. While we have plans to upgrade Angular at some point to the latest version, we simply haven’t had an opportunity yet…

The Angular project requires Node.js 10.x, and does not support greater versions.

I’ve been investigating if we can utilize one of the NVM (Node.js Version Manager) systems to allow us to better manage multiple installations of Node.js on a build agent. It seems like there may also be some further project configuration that can be done.

Our goal is to keep our build pipelines as portable as possible, which means as little machine configuration outside of the pipeline. The Azure Pipeline should be able to install any tools it needs, and make them available to the tasks of the pipeline.

Going forward, my plan is to install the latest version of Node.js on our build server, and then use NVM to switch out which version of Node.js our Angular project is being built against during that stage of our pipeline. Eventually, I’d like to not have to install Node.js at all on the target machine, but instead allow the Pipeline to download the tools and point to them by changing the PATH environment variable during the execution of the pipeline.

I will report back with expanded detail if this works for us. It would still be very helpful if Sonar checked the PATH environment variable for Node.js before falling back to the WHERE command.

Hi @crush,

Were you able to fix your issue?