Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-62993

Auto-detect NodeJS-Tool based on package.json engines.node version

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      As described in nodejs docs] you can specify the nodejs version suitable for your project in package.json.

      I think it would be nice if one could write something like this in pipeline:

      nodejsAutodetect {
          // your node and npm scripts
      }

      and then nodejs-plugin would scan all installed versions of node and check whether the version fits or not. If it fits it would use that version for the block.

      I have created a groovy script in a shared library for my current project which does that. It is far from perfect, but i think a good proof of concept:

      import jenkins.plugins.nodejs.NodeJSUtils;
      
      @Grab('com.vdurmont:semver4j:3.1.0')
      import com.vdurmont.semver4j.Semver
      
      @NonCPS
      def determineInstalledNodeJSVersions() {
        def installedNodeJSVersions = [:]
        NodeJSUtils.getInstallations().each { entry ->
          def name = entry.getName()
          def version = entry.getProperties()[0].installers[0].id
          installedNodeJSVersions[name] = version
        }
        return installedNodeJSVersions.sort({it1, it2 -> it2.value <=> it1.value})
      }
      
      def nodejsAutodetect(Closure body) {
      
        def availableVersions = determineInstalledNodeJSVersions()
        // get lastest version
        def latestNodeJS = map.find { true }
        def nodeJSToUse = latestNodeJS.key
      
        if(!env.DETECTED_NODEJS_VERSION) {
          def packageJson = readJSON file: 'package.json'
          if(packageJson['engines'] && packageJson['engines']['node']) {
            versionString = packageJson['engines']['node']
            
            availableVersions.find { entry ->
              Semver semNPM = new Semver(entry.value, Semver.SemverType.NPM)    
              if(semNPM.satisfies(versionString)) {
                nodeJSToUse = entry.key
                env.DETECTED_NODEJS_VERSION = nodeJSToUse
                return true
              } else {
                return false
              }
            }
          } else {
            println "Did not find 'node' entry in package.json, so using latest installed nodejs."
          }
        } else {
          nodeJSToUse = env.DETECTED_NODEJS_VERSION
        }
      
        nodejs(nodeJSToUse) {
          body()
        }
      }
      

      I think it would be a nice improvement for your library.

      I am exited to hear what you think about it.

        Attachments

          Activity

          andi_bade Andi Bade created issue -
          andi_bade Andi Bade made changes -
          Field Original Value New Value
          Description As described [in nodejs docs|#engines]] you can specify the nodejs version suitable for your project in package.json.

          I think it would be nice if one could write something like this in pipeline:
          {code}
          nodejsAutodetect {
              // your node and npm scripts
          }{code}
          and then nodejs-plugin would scan all installed versions of node and check whether the version fits or not. If it fits it would use that version for the block.

          I have created a groovy script in a shared library for my current project which does that. It is far from perfect, but i think a good proof of concept:
          {code}
          import jenkins.plugins.nodejs.NodeJSUtils;
          @NonCPS
          def determineInstalledNodeJSVersions() {
            def installedNodeJSVersions = [:]
            NodeJSUtils.getInstallations().each { entry ->
              def name = entry.getName()
              def version = entry.getProperties()[0].installers[0].id
              installedNodeJSVersions[name] = version
            }
            return installedNodeJSVersions.sort({it1, it2 -> it2.value <=> it1.value})
          }

          def nodejsAutodetect(Closure body) {

            def availableVersions = determineInstalledNodeJSVersions()
            // get lastest version
            def latestNodeJS = map.find { true }
            def nodeJSToUse = latestNodeJS.key

            if(!env.DETECTED_NODEJS_VERSION) {
              def packageJson = readJSON file: 'package.json'
              if(packageJson['engines'] && packageJson['engines']['node']) {
                versionString = packageJson['engines']['node']
                dir('detect-node-tmp') {
                  nodejs(latestNodeJS.key) {
                    sh "npm install semver"
                    availableVersions.find { entry ->
                      def satisfies = sh(returnStdout: true,
                        script: "node -e \"console.log(require('semver').satisfies('${entry.value}', '${versionString}') ? 'true' : 'false')\"",
                        label: "Test Node Version").trim()

                      if(satisfies == 'true') {
                        nodeJSToUse = entry.key
                        env.DETECTED_NODEJS_VERSION = nodeJSToUse
                        return true
                      } else {
                        return false
                      }
                    }
                  }
                }
              } else {
                println "Did not find 'node' entry in package.json, so using latest installed nodejs."
              }
            } else {
              nodeJSToUse = env.DETECTED_NODEJS_VERSION
            }

            nodejs(nodeJSToUse) {
              body()
            }
          }
          {code}
          I think it would be a nice improvement for your library.

          I am exited to hear what you think about it.
          As described [in nodejs docs|#engines]] you can specify the nodejs version suitable for your project in package.json.

          I think it would be nice if one could write something like this in pipeline:
          {code:java}
          nodejsAutodetect {
              // your node and npm scripts
          }{code}
          and then nodejs-plugin would scan all installed versions of node and check whether the version fits or not. If it fits it would use that version for the block.

          I have created a groovy script in a shared library for my current project which does that. It is far from perfect, but i think a good proof of concept:
          {code:java}
          import jenkins.plugins.nodejs.NodeJSUtils;

          @Grab('com.vdurmont:semver4j:3.1.0')
          import com.vdurmont.semver4j.Semver

          @NonCPS
          def determineInstalledNodeJSVersions() {
            def installedNodeJSVersions = [:]
            NodeJSUtils.getInstallations().each { entry ->
              def name = entry.getName()
              def version = entry.getProperties()[0].installers[0].id
              installedNodeJSVersions[name] = version
            }
            return installedNodeJSVersions.sort({it1, it2 -> it2.value <=> it1.value})
          }

          def nodejsAutodetect(Closure body) {

            def availableVersions = determineInstalledNodeJSVersions()
            // get lastest version
            def latestNodeJS = map.find { true }
            def nodeJSToUse = latestNodeJS.key

            if(!env.DETECTED_NODEJS_VERSION) {
              def packageJson = readJSON file: 'package.json'
              if(packageJson['engines'] && packageJson['engines']['node']) {
                versionString = packageJson['engines']['node']
                
                availableVersions.find { entry ->
                  Semver semNPM = new Semver(entry.value, Semver.SemverType.NPM)
                  if(semNPM.satisfies(versionString)) {
                    nodeJSToUse = entry.key
                    env.DETECTED_NODEJS_VERSION = nodeJSToUse
                    return true
                  } else {
                    return false
                  }
                }
              } else {
                println "Did not find 'node' entry in package.json, so using latest installed nodejs."
              }
            } else {
              nodeJSToUse = env.DETECTED_NODEJS_VERSION
            }

            nodejs(nodeJSToUse) {
              body()
            }
          }
          {code}
          I think it would be a nice improvement for your library.

          I am exited to hear what you think about it.
          nfalco Nikolas Falco made changes -
          Resolution Won't Do [ 10001 ]
          Status Open [ 1 ] Closed [ 6 ]

            People

            Assignee:
            nfalco Nikolas Falco
            Reporter:
            andi_bade Andi Bade
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved: