跳转到内容

CNB 流水线导出环境变量

868 字 3 分钟

属性 2
author
wwvo
status
Active

CNB 流水线导出环境变量

这篇文档只讲一件事:在 CNB 流水线里,怎么把前一个 stage 的结果传给后一个 stage。

最常见的场景:

  • 前一个 stage 计算出一个版本号
  • 前一个 stage 生成一段 Release 描述
  • 前一个 stage 读取一个文件内容,后一个 stage 继续使用

1. 最短结论

CNB 里“导出环境变量”不是直接写:

bash
export MY_VAR=hello

这样 不够

正确做法是两步:

  1. 在脚本输出里用 ##[set-output ...] 写入结果
  2. exports 里把这个结果映射成后续 stage 可用的环境变量

2. 最简单示例

yml
main:
  push:
    - stages:
        - name: prepare
          script:
            - echo "##[set-output message=hello world]"
          exports:
            message: MY_MESSAGE

        - name: use
          script:
            - echo "$MY_MESSAGE"

执行效果:

  • 第一个 stage 输出 message=hello world
  • exportsmessage 导出成环境变量 MY_MESSAGE
  • 第二个 stage 可以直接用 $MY_MESSAGE

3. 为什么单纯 export 不行

很多人会这样写:

yml
- name: prepare
  script:
    - export MY_MESSAGE=hello
  exports:
    MY_MESSAGE: MY_MESSAGE

这通常是错的。

原因是:

  • export MY_MESSAGE=hello 只是当前 shell 进程里的环境变量
  • CNB 的 exports 读取的是当前 Job 的 result 对象
  • result 里默认只有 stdoutstderrinfocode 等字段
  • 自定义字段必须通过 ##[set-output key=value] 写进去

所以,exports 左边的 key,应该是:

  • stdout
  • stderr
  • info
  • code
  • 或者你自己通过 set-output 生成的字段名

4. 标准写法

推荐你默认这样写:

yml
- name: prepare
  script:
    - |
      value="hello world"
      echo "##[set-output message=$value]"
  exports:
    message: MY_MESSAGE

后面直接使用:

yml
- name: use
  script:
    - echo "$MY_MESSAGE"

5. 多行内容怎么导出

如果变量里有换行,例如:

  • Markdown 文本
  • Release 描述
  • 一段日志摘要

不要直接硬塞普通字符串,推荐使用 base64

示例:

yml
- name: prepare-description
  script:
    - |
      description="$(cat <<EOF
      这是标题

      这是第二段
      EOF
      )"
      encoded="$(printf '%s' "$description" | base64 -w 0)"
      echo "##[set-output release_description=base64,$encoded]"
  exports:
    release_description: RELEASE_DESCRIPTION

- name: use-description
  script:
    - echo "$RELEASE_DESCRIPTION"

这样做的好处:

  • 能保留换行
  • 不容易被 shell 特殊字符干扰
  • 更适合传 Markdown 或较长文本

6. 在 git:release 里使用导出的变量

CNB 的内置任务 options 支持变量替换,所以可以这样写:

yml
- name: prepare-release-description
  script:
    - |
      description="发布说明正文"
      encoded="$(printf '%s' "$description" | base64 -w 0)"
      echo "##[set-output release_description=base64,$encoded]"
  exports:
    release_description: RELEASE_DESCRIPTION

- name: release
  type: git:release
  options:
    title: v1.0.0
    description: "$RELEASE_DESCRIPTION"

这就是最常见的“前一个 stage 生成 release 描述,后一个 stage 创建 release”的写法。

7. 常见坑

7.1 误以为 export 就够了

错误示例:

bash
export RELEASE_DESCRIPTION=hello

这不会自动进入 CNB 的 exports

7.2 多行文本不编码

如果文本里有换行,建议直接用 base64,不要赌 shell 解析细节。

7.3 代码块里的反引号被 shell 误解析

比如你在 here-doc 里直接写:

text
```text
hello
```

有些 shell 场景下可能把反引号当命令替换处理,导致内容丢失或报错。

更稳妥的方式:

  • ~~~text 代码块
  • 或先把内容放变量里,再拼接字符串

7.4 变量太长

CNB 文档里提到:

  • 环境变量值不能超过 100 KiB
  • 太大的值会被忽略

如果内容很大,建议改成:

  • 写文件
  • 后续 stage 再读文件

8. 一个实用模板

yml
main:
  push:
    - stages:
        - name: prepare
          script:
            - |
              text="$(cat <<EOF
              第一行

              第二行
              EOF
              )"
              encoded="$(printf '%s' "$text" | base64 -w 0)"
              echo "##[set-output result_text=base64,$encoded]"
          exports:
            result_text: RESULT_TEXT

        - name: use
          script:
            - echo "$RESULT_TEXT"

记住这 3 行就够了:

bash
encoded="$(printf '%s' "$text" | base64 -w 0)"
echo "##[set-output result_text=base64,$encoded]"

然后在 YAML 里:

yml
exports:
  result_text: RESULT_TEXT

9. 一句话总结

在 CNB 里,跨 stage 传值的关键不是 shell 的 export,而是 set-output + exports

如果是多行文本,优先用:

  • base64
  • exports
  • 后续 stage 用 $ENV_NAME