【问题标题】:Docker Jenkins Pipeline install global NPM packagesDocker Jenkins Pipeline 安装全局 NPM 包
【发布时间】:2019-06-26 17:01:43
【问题描述】:

我是 Docker/Jenkins 的新手。

Jenkins 通过

触发容器
docker run -t -d -u 995:315 -w /workspace/projectname -v /workspace/projectname:/workspace/projectname:rw,z -v /workspace/projectname@tmp:/workspace/projectname@tmp:rw,z  circleci/node:latest

我的管道

pipeline {
    agent {
        docker {
            image 'circleci/node:latest'
        }
    }
    environment { 
        HOME="."
        NPM_CONFIG_PREFIX="${pwd()}/.npm-global"
        PATH="$PATH:${pwd()}/.npm-global/bin:${pwd tmp: true}/.npm-global/bin"
    }
    stages {
        stage('NPM Config') {
            steps {
                sh 'npm install -g @angular/cli'
                echo "PATH is: $PATH"
                sh '.npm-global/bin/ng version'
                sh '/workspace/projectname/.npm-global/bin/ng version'
                sh 'ng version'
            }
        }
    }
}

echo "PATH is: $PATH" 打印出来

PATH is: /sbin:/usr/sbin:/bin:/usr/bin;/usr/bin/;/etc/;/etc/ssh/ssh/:/workspace/projectname/.npm-global/bin:/workspace/projectname@tmp/.npm-global/bin

这两个

sh '.npm-global/bin/ng version'
sh '/workspace/projectname/.npm-global/bin/ng version'

做我期望sh 'ng version' 做的事情。但是,sh 'ng version' 给了我以下错误

ng version
/workspace/projectname@tmp/durable-9f9bc04a/script.sh: 2: /workspace/projectname@tmp/durable-9f9bc04a/script.sh: ng: not found

我正在努力避免建立自己的形象,下一步该怎么做?

我也只会使用npx,但我需要更改很多存储库及其脚本才能使这项工作正常进行,我不想这样做。

更新:看起来管道正在忽略更改下的 PATH 环境变量

environment { 
   HOME="."
   NPM_CONFIG_PREFIX="${pwd()}/.npm-global"
   PATH="/foo/bar"
}

是否有特殊的修改路径的可能?或者可能是权限问题?

【问题讨论】:

  • 谢谢,但这真的不是我的问题,不是角度问题,我只是试图简化这个问题,希望我错过了一些简单的东西。如果这就是我所需要的,我会很好,但不幸的是它不是。
  • 在调用sh 'echo "PATH is $PATH"' 而不是直接echoing 时,您的PATH 是否仍然“更新”? (考虑在某个地方需要一个可能的export PATH,尽管它不应该是这种情况......)
  • @StockOverflaw 认为这两者是相同的,但我只是检查并将其更改为sh 'echo $PATH' 打印出默认路径,而不是通过echo "PATH is: $PATH" 的路径有什么想法可以解决这个问题吗?导出路径也不起作用
  • 这意味着当调用sh 时,管道会生成一个子进程(如输出摘录here 所建议的那样)。我不知道这是否合法,但如果你尝试像这样在声明前加上前缀,詹金斯会不会很生气:export PATH=$PATH:${pwd()}/blahblah/and/so/on?既然是export 定义,就允许孩子检索这些变量...

标签: node.js docker jenkins npm


【解决方案1】:

这是一个格式化的,希望有用的答案,在尝试使用他们的详细文档进行整理之后。

首先,environment 块声明了 Jenkins 级别的键值对:

  • Jenkins级别不是workspace级别,变量插值级别是根据引号的类型来选择的,所以如果我理解正确的话:

    echo '$PATH' 将显示工作区PATH(在您的情况下为“默认”)

    echo "$PATH" 将由 Jenkins 解释,因此显示“修改后的”PATH

  • 只有键值对是有效的:即使它看起来像 shell 环境变量设置,你也可以写 PATH = something= 周围的空格在 shell 中不起作用

似乎主要是在工作区不知道参数的情况下公开参数,就像用户会交互式地提供信息(他们经常谈论凭据)。

其次,只有有限的steps列表进行有效调用,没有export步骤。

但是有一个withEnv 步骤应该可以完成这项工作。我没有在声明性 pipeline { ... } 中找到任何示例,仅在脚本化 node { ... } 块中,声明性版本的定义声明所有步骤都是有效的。我找到了一个包装stage 块的步骤示例(尽管在node 中),所以我们希望stages 是相同的(否则你必须在每个stage 上指定withEnv -或作为stage 中的另一个包装器 - 这需要您的环境模块:当然可行但很无聊)。

这样的事情应该可以工作,或者至少值得一试:

  pipeline {
    agent { ... }
    environment { 
      HOME="."
      NPM_CONFIG_PREFIX="${pwd()}/.npm-global"
      PATH="$PATH:${pwd()}/.npm-global/bin:${pwd tmp: true}/.npm-global/bin"
    }
    withEnv(["PATH=$PATH", /*or*/ "PATH=${PATH}", /*or*/ "PATH+NPM=${pwd()}/.npm-global/bin:${pwd tmp: true}/.npm-global/bin"]) {
      stages {
        stage('NPM Config') {
          steps { ... }
        }
        stage('something else that needs ng') { ... }
      }
    }
  }

嗯,你明白了。

最后,如果 PATH 的事情不起作用并且比重写管道更困扰您,使用带有 node 块的脚本替代方案可能会更有趣且更灵活。

我希望得到 OP 或周围任何 Jenkins 专家的反馈!

【讨论】:

  • 感谢您提供详细信息。我也已经尝试过“withenv”选项,但它仍然给我带来了问题。似乎容器不想让“PATH”在运行时更新......所以最后我认为最好的选择是将图像配置为我们需要的设置并从那里开始。我只是想避免这种情况,但由于似乎没有明确的答案,我的猜测是每个人都只是创建一个新图像。再次感谢您在这方面与我合作
【解决方案2】:

如果您使用声明式管道进行构建,那么全局安装任何东西是没有意义的。

如果您在管道执行期间安装“angular-cli”,npm 将为您设置 PATH 变量,并且 ng 将可用。

如果您构建自己的映像并计划稍后重用它,全局安装是有意义的。但在这种情况下,镜像将在构建后被删除。

在这种情况下,我使用sh "ls -la1 $dir_name"sh "whereis ng" 来调试“找不到可执行文件”问题。

此外,如果您使用声明式管道,您可以使用最轻的图像而无需 CI 绑定。 我用node:8.11.3-stretch

【讨论】:

  • 您能否详细说明一下为什么使用声明性管道在全局范围内安装任何东西没有意义?
  • 如果您在管道期间安装“angular-cli”,npm 将为您设置 PATH 变量,并且 ng 将可用。如果您构建自己的映像并计划稍后重用它,则全局安装是有意义的。但是在这种情况下,镜像会在构建完成后被删除。
  • 是的,我知道我什至可以使用 NPX 来运行全局包问题是我们有大约 10 个不同的项目,并且都需要更新它们的脚本才能以这种方式运行它们。如果可能的话,我会尽量避免这种情况,而且它不仅仅是有角度的,我们还使用了一些其他 CLI 类型的工具(本地开发的包)
  • 我们把 Dockerfile 放到项目根目录下。 ` 代理 { dockerfile { 文件名 'Dockerfile' } } `
  • 然后我调试这种情况,我看到两个选项。在预期位置找不到文件。文件权限不足。
【解决方案3】:

正确的方法是使用 Jenkins 的 Node.js 插件。 它允许您管理不同版本的 node 和 npm 包,而无需手动将它们安装在构建机器上。 这是一个全局使用节点 13 和 eslint 的配置示例:

在您的管道中,您可以这样做:

stage('Use node commands and npm packages') {
  steps {
    nodejs(nodeJSInstallationName: 'node13') {
      sh 'npm -v'  //substitute with your code
      sh 'node -v'
      sh 'eslint ...'
    }
  }
}

完整示例:https://pillsfromtheweb.blogspot.com/2020/05/how-to-use-different-nodejs-versions-on.html

【讨论】:

    猜你喜欢
    • 2017-11-05
    • 2020-10-23
    • 1970-01-01
    • 2021-04-13
    • 2023-04-03
    • 2019-12-22
    • 2018-06-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多