曾静的博客

但行好事,莫问前程.

嗨,我是曾静 (@devzeng),目前暂居深圳。


这是我用来记录平日学习笔记的地方,欢迎您的访问.

Jenkins Pipeline 插件自定义环境变量丢失问题

最近将一些构建任务由 Freestyle 迁移为 Pipeline 的实现 (主要是考虑后续可以通过任务模板的方式动态创建和维护),整体的实现过程较为简单,基本上就是把原来的执行步骤拆分成一个个的 Stage,将里面用到的一些配置抽取成环境变量的方式,统一设置到一起。

最终的配置脚本如下(伪代码):

node("mac01") {
    stage('Environment Setting') {
        env.ENV_BUILD_SCRIPT_URL = "http://127.0.0.1:8080/test/script.zip"
        env.ENV_BUILD_CONFIG_NAME = "xxxxx"
        env.ENV_BUILD_XCODE_PATH = "/Applications/Xcode-14.3.1.app"
    }

    try {
        stage('Download Source Code') {
            // ...
        }

        stage('Build Project') {
            executeScript ext: '', path: '${WORKSPACE}/script.zip', url: "${ENV_BUILD_SCRIPT_URL}", commandLine: '''
                export LANG=en_US.UTF-8
                [ -d "${ENV_BUILD_XCODE_PATH}" ] && export DEVELOPER_DIR="${ENV_BUILD_XCODE_PATH}/Contents/Developer"
                cd ${WORKSPACE}/script
                ./build --config "${ENV_BUILD_CONFIG_NAME}" --job_name "${JOB_BASE_NAME}" --job_id "${BUILD_ID}" --branch "${BRANCH}" --workspace "${WORKSPACE}" --verbose
            '''
        }
        
        stage('Upload Artifactory') {
            //....
        }

        stage('Clean Workspace') {
            cleanWs()
        }
    } catch(e) {
        // ...
        cleanWs()
        throw e
    }
}

运行过程中发现执行命令行的时候,环境变量 ENV_BUILD_XCODE_PATHENV_BUILD_CONFIG_NAME 获取不到,但是写一个单独的脚本执行却能正常打印出来:

sh label: '', script: '''
    export LANG=en_US.UTF-8
    echo $ENV_BUILD_CONFIG_NAME
    echo $ENV_BUILD_XCODE_PATH
'''

executeScript 是一个自定义的插件,用于下载脚本工具(下载完成后会自动注入一些通用的上下文数据),并执行指定的命令。

plugin_settings

怀疑是不是插件实现的代码有问题,可能忘了对命令行字符串里面的环境变量进行替换。看了一下代码,在插件内部的主要实现是获取当前的执行环境变量,然后对命令脚本字符串的变量进行替换,核心代码如下:

EnvVars env = getPipelineEnvironment(run, filePath, listener);
commandLine = env.expand(commandLine);

获取 Pipeline 的环境变量的方法:

public static EnvVars getPipelineEnvironment(Run<?, ?> run, FilePath filePath, TaskListener listener) throws IOException, InterruptedException {
    EnvVars env = run.getEnvironment(listener);
    if (!env.containsKey("WORKSPACE") && filePath != null) {
        env.put("WORKSPACE", filePath.getRemote());
    }
    return env;
}

咋一看没啥毛病,在 env.expand 之前下了一个断点,查看了一下 env (其实内容是一个字典),确实没有找到前面定义的 ENV_ 开头的自定义环境变量。查了一些资料发现获取环境变量的代码都是上面这段代码(其实这段代码也是从网上Copy来的)。通过对 getPipelineEnvironment 下断点发现通过获取action里面的EnvActionImpl的数据可以拿到想要的环境变量的数据:

stack_value

那就好办了,只要拿到 Action 列表遍历判断是不是 EnvActionImpl(org.jenkinsci.plugins.workflow.cps.EnvActionImpl) 这个Action,然后把 env 属性对应的数据拿出来就完成了。本来打算通过动态Class获取,搜索了一番发现可以直接通过添加依赖集成。在 pom.xml 中添加依赖

<dependency>
    <groupId>org.jenkins-ci.plugins.workflow</groupId>
    <artifactId>workflow-cps</artifactId>
    <version>2.41</version>
</dependency>

修改上面的 getPipelineEnvironment 方法增加如下代码:

Iterator envActionIterator = run.getActions(EnvActionImpl.class).iterator();
while(envActionIterator.hasNext()) {
    EnvActionImpl a = (EnvActionImpl)envActionIterator.next();
    env.putAll(a.getEnvironment());
}

重新运行,一切正常,重新打包,发布。

参考资料

最近的文章

Xcode15和iOS17相关的问题解决

近期在做一些适配相关的工作,在适配过程中踩到了一些坑。这是一篇水文,主要是记录 iOS 17 和 Xcode 15 适配过程中遇到的一些问题和解决方法。1、Xcode 14 在 iOS 17 的真机上运行一般来说Xcode和iOS系统匹配才能运行,但是有些时候不想升级Xcode但是想要在高版本的iOS真机上面调试项目。首先从别人升级过Xcode的电脑上面拷贝 DeviceSupport 目录下对应版本的镜像文件过来就行了,目录如下:/Applications/Xcode.app/Conte...…

Note继续阅读
更早的文章

macOS SSH 登录账号过期问题解决

近期对构建环境的几台 Mac Mini 做了一些“标准化”处理,处理完成后发现通过ssh访问输入密码无法正常连接了(按回车会立即提示连接结束)。通过查看控制台日志发现有如下的记录:错误信息:error: PAM: user account has expired for xxxx from 127.0.0.1各种查找资料没有找到能讲清楚这个问题原因的,经过一番测试发现一种解决办法:(1) 查看是否打开共享的远程登录 旧版的系统(<= macOS 12) 新版的系统(>= m...…

Note继续阅读