环境变量

在构建过程中可以使用环境变量,云原生构建 内置了一些默认环境变量

声明环境变量

  1. 通过 env 声明环境变量
  2. Pipeline 里声明的环境变量对当前 Pipeline 有效
  3. Job 里声明的环境变量对当前 Job 有效
 1main:
 2  push:
 3    - env:
 4        RELEASE_MSG: release message
 5      stages:
 6        - name: release
 7          type: git:release
 8          env:
 9            RELEASE_NAME: release-1
10          options:
11            description: ${RELEASE_MSG}
12            name: ${RELEASE_NAME}

导入环境变量

  1. 通过 imports 导入一个密钥仓库文件,可将敏感信息注入到环境变量,供后续任务使用。
  2. envimportskey 冲突时,优先使用 env
 1main:
 2  push:
 3    - services:
 4        - docker
 5      # 导入密钥仓库文件为环境变量
 6      imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/envs.yml
 7      stages:
 8        - name: docker info
 9          script: docker info
10        - name: docker login
11          # 其中 TEST_DOCKER_DOMAIN、TEST_DOCKER_USER、TEST_DOCKER_PWD 为密钥仓库文件中的变量
12          script: docker login $TEST_DOCKER_DOMAIN -u $TEST_DOCKER_USER -p $TEST_DOCKER_PWD

https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/envs.yml 内容示例

1# docker 镜像源域名
2TEST_DOCKER_DOMAIN: registry.example.com
3# docker 用户名
4TEST_DOCKER_USER: your_docker_username
5# docker 密码
6TEST_DOCKER_PWD: your_docker_password

变量名限制

在 Shell 中,环境变量名的命名规则有一些限制。根据 POSIX 标准,环境变量名应符合以下规则:

  1. 只能包含字母(大小写均可)、数字和下划线(_)字符。
  2. 第一个字符不能是数字。

不符合上述规则的变量会被忽略

导出环境变量

Job 执行结束后,有一个 result 对象,可通过 exportsresult 中的属性导出到环境变量,生命周期为当前 Pipeline

语法格式为:

1exports:
2  from-key: to-key

有如下三种方式设置 result:

脚本任务执行结果

script 自定义脚本任务执行完,Job result的属性有:

注意:可使用 printf "%s" "hello\nworld" 来输出变量,以消除标准输出流最后的换行符,同时保留 \n 等转义字符。

 1main:
 2  push:
 3    - stages:
 4        - name: set env
 5          script: echo -n $(date "+%Y-%m-%d %H:%M")
 6          exports:
 7            code: CUSTOM_ENV_DATE_CODE
 8            info: CUSTOM_ENV_DATE_INFO
 9        - name: echo env
10          script:
11            - echo $CUSTOM_ENV_DATE_CODE
12            - echo $CUSTOM_ENV_DATE_INFO

包含 ififModifyifNewBranch 等判断逻辑时,可设置的属性有:

1- name: use if
2  if: exit -1
3  exports:
4    skip: REASON
5- name: tell last
6  # $REASON 的值为 if 这个字符串
7  script: echo $REASON

解析输出中的自定义变量

CI 会从标准输出流里按行识别 ##[set-output key=value] 格式的内容,自动放入 result 对象中。

若变量值包含换行符 \n,可对变量值进行 base64escape 编码。

变量值若以 base64, 开始,云原生构建 会对 base64, 后面的内容做 base64 解码,否则会对变量值做 unescape 解码。

使用 Node.js 示例代码如下:

1// test.js
2const value = "测试字符串\ntest string";
3// 输出 base64 编码的变量值
4console.log(
5  `##[set-output redline_msg_base64=base64,${Buffer.from(value, "utf-8").toString("base64")}]`,
6);
7
8// 输出 escape 编码的变量值
9console.log(`##[set-output redline_msg_escape=${escape(value)}]`);
 1main:
 2  push:
 3    - docker:
 4        image: node:20-alpine
 5      stages:
 6        - name: set output env
 7          script: node test.js
 8          # 将 test.js 输出的变量导出为环境变量
 9          exports:
10            redline_msg_base64: BASE64_KEY
11            redline_msg_escape: ESCAPE_KEY
12        - name: echo env
13          script:
14            - echo "BASE64_KEY $BASE64_KEY"
15            - echo "ESCAPE_KEY $ESCAPE_KEY"

使用 echo 示例代码如下:

 1main:
 2  push:
 3    - stages:
 4        - name: set output env
 5          script: echo "##[set-output redline_msg_base64=base64,$(echo -e "测试字符串\ntest string" | base64 -w 0)]"
 6          exports:
 7            redline_msg_base64: BASE64_KEY
 8        - name: echo env
 9          script:
10            - echo -e "BASE64_KEY $BASE64_KEY"

注意:在 Unix-like 系统中,base64 命令默认会在每76个字符后添加一个换行符,可使用 -w 0 选项来禁用换行避免 CI 未能按行解析出变量。

不包含 \n 的变量值可直接输出

1echo "##[set-output redline_msg=some value]"

:::tip 受限于系统环境变量值长度限制,过大的变量值无效。

CI 会忽略大于等于 100KB 的变量值。可写入文件中自行解析。

对于敏感信息,建议使用 read-file 内置任务。 :::

内置任务中导出环境变量

一些内置任务会有输出结果,可通过 exports 导出为环境变量。

 1main:
 2  push:
 3    - stages:
 4        - name: xxxx
 5          type: xxx:xxx
 6          options:
 7            product: public
 8            name: cnb
 9            dist: release/
10          exports:
11            version: CUSTOM_ENV_VERSION
12            url: CUSTOM_ENV_URL
13            #支持对象深层取值
14            nextRelease.gitTag: CUSTOM_ENV_GIT_TAG
15        - name: echo env
16          script:
17            - echo $CUSTOM_ENV_VERSION
18            - echo $CUSTOM_ENV_URL

result 内容参考各内置任务文档。

增删改查环境变量

可以覆盖已有的环境变量,设为空字符串或 null 即为删除。

 1main:
 2  push:
 3    - env:
 4        CUSTOM_ENV_DATE_INFO: default
 5        CUSTOM_ENV_FOR_DELETE: default
 6      stages:
 7        - name: set env
 8          script: echo -n $(date "+%Y-%m-%d %H:%M")
 9          exports:
10            # 新增
11            code: CUSTOM_ENV_DATE_CODE
12            # 修改
13            info: CUSTOM_ENV_DATE_INFO
14            # 删除
15            CUSTOM_ENV_FOR_DELETE: null
16            # 删除
17            # CUSTOM_ENV_FOR_DELETE:
18        - name: echo env
19          script:
20            - echo $CUSTOM_ENV_DATE_CODE
21            - echo $CUSTOM_ENV_DATE_INFO
22            - echo $CUSTOM_ENV_DATE_STDOUT
23            - echo $CUSTOM_ENV_FOR_DELETE
24            - echo $CUSTOM_ENV_GIT_TAG

使用环境变量

在 脚本任务 中使用

执行脚本任务时,流水线设置的环境变量作为任务执行时的环境变量

 1main:
 2  push:
 3    - stages:
 4        - name: test internal env
 5          # CNB_BRANCH 为内置环境变量
 6          script: echo $CNB_BRANCH
 7        - name: test self defined env
 8          env:
 9            cat_name: tomcat
10          script: echo $cat_name

变量替换

配置文件中的一些属性值会进行变量替换。

如有环境变量 env_name=env_value,那么属性值中 $env_name 会被替换成 env_value,若 env_name 无值,则会替换成空字符串。

下面列出了会进行变量替换的属性:

内置任务 options 内的属性值和 optionsFrom 会进行变量替换。

1# options.yml
2name: Nightly
 1main:
 2  push:
 3    - env:
 4        address: options.yml
 5        description: publish for xx task
 6      stages:
 7        - name: git release
 8          type: git:release
 9          # $address 会被替换成 env 中的 "options.yml"
10          optionsFrom: $address
11          # options.yml 中的 name 会合并到 options 中
12          options:
13            # $description 会被替换成 env 中的 "publish for xx task"
14            description: $description

options 的最终内容为:

1name: Nightly
2description: publish for xx task

插件任务 settings 内的属性值和 settingsFrom 会进行变量替换。

1# settings.yml
2robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
 1main:
 2  push:
 3    - env:
 4        address: settings.yml
 5        message: pr check
 6      stages:
 7        - name: notify
 8          image: tencentcom/wecom-message
 9          # $address 会被替换成 env 中的 "settings.yml"
10          settingsFrom: $address
11          # settings.yml 中的 robot 会合并到 settings 中
12          settings:
13            # $message 会被替换成 env 中的 "pr check"
14            content: $message

settings 的最终内容为:

1robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
2message: pr check

另外写在 Dockerfile 中的 LABEL 指定的 settingsFrom 同样可以进行变量替换

1FROM node:20
2
3LABEL cnb.cool/settings-from="$address"

env 下声明的属性值可以引用上层 env 中的变量进行替换

 1# .cnb.yml
 2main:
 3  push:
 4    - env:
 5        cat_name: tomcat
 6      stages:
 7        - name: echo env
 8          env:
 9            # 使用上层 env 声明的 cat_name 值进行替换
10            name: "cat $cat_name"
11            # 输出 cat tomcat
12            script: echo $name

imports 的属性值以及所声明的文件中的属性值均会进行变量替换。

若 imports 为数组,数组前面文件中声明的变量对数组后面元素有效。

1# env1.yml
2address: env2.yml
3platform: amd64
1# env2.yml
2# 读取 env1.yml 中的 platform 属性值进行替换
3action: build for $platform
 1# .cnb.yml
 2main:
 3  push:
 4    - imports:
 5        - env1.yml
 6        # env1.yml 中声明了 address,$address 会被替换成 env2.yml
 7        - $address
 8      stages:
 9        - name: echo action
10          # 读取 env2.yml 中的 action 属性值进行替换
11          script: echo $action
 1# 构建不同架构下的镜像
 2.build: &build
 3  runner:
 4    tags: cnb:arch:$CNB_PIPELINE_NAME
 5  services:
 6    - docker
 7  stages:
 8    - name: docker build
 9      script: echo "docker build for $CNB_PIPELINE_NAME"
10main:
11  push:
12    # 下面 "amd64" 和 "arm64:v8" 会被声明为内置环境变量 CNB_PIPELINE_NAME 的值
13    amd64: *build
14    "arm64:v8": *build
 1.docker-volume: &docker-volume
 2  docker:
 3    image: node:22-alpine
 4    volumes:
 5      - $volume_path
 6main:
 7  push:
 8    install:
 9      env:
10        volume_path: node_modules
11      <<: *docker-volume
12      stages:
13        - name: install
14          script: npm install axios
15        # 通知其他流水线执行
16        - name: resolve
17          type: cnb:resolve
18          options:
19            key: install
20    build:
21      env:
22        volume_path: node_modules
23      <<: *docker-volume
24      stages:
25        # 等待 install 流水线
26        - name: await
27          type: cnb:await
28          options:
29            key: install
30        - name: ls
31          script: ls node_modules
 1# 不同模块下代码有变更才进行对应模块的编译
 2.build: &build
 3  ifModify: $CNB_PIPELINE_NAME/*
 4  stages:
 5    - name: build $CNB_PIPELINE_NAME
 6      script: echo "build $CNB_PIPELINE_NAME"
 7main:
 8  push:
 9    module-a: *build
10    module-b: *build

pipeline.name 、stage.name 和 job.name 的属性值会进行变量替换。

 1main:
 2  push:
 3    - name: build in $CNB_REPO_SLUG
 4      env:
 5        platform: amd64
 6      imports:
 7        - env1.yml
 8        - env2.yml
 9      stages:
10        - name: stage_$SOME_ENV
11          script: echo "hello world"
1# env.yml
2build_key: build key
 1.build: &build
 2  imports: env.yml
 3  lock:
 4    key: $build_key
 5  stages:
 6    - name: echo
 7      script: echo "hello world"
 8main:
 9  push:
10    # 以下两条流水线,一条占用了锁成功执行,另一条位占到锁执行失败
11    - *build
12    - *build
1main:
2  push:
3    - env:
4        allow_fail: true
5      stages:
6        - name: echo
7          allowFailure: $allow_fail
8          # 脚本执行会报错,但 allowFailure 为 true,任务被认为是成功的
9          script: echo1 1

阻止变量替换

如果不希望 $env_name 被替换,可以通过 \$ 阻止替换

1main:
2  push:
3    - stages:
4        - name: git release
5          type: git:release
6          options:
7            name: Development
8            # 属性值是 "some code update $description"
9            description: some code update \$description

限制

环境变量名需由字母、数字或 _ 组成,不能以数字开头。

变量值的长度不能超过 100KiB