Environment Variables
About 1939 wordsAbout 6 min
Cloud Native Build not only supports declaring the build environment but also allows defining environment variables used within the build environment.
Cloud Native Build comes with some default environment variables for direct use.
Feature Overview
Environment variables support the following features:
| Feature | Description |
|---|---|
| Declare Environment Variables | Declare environment variables via env |
| Import Environment Variables | Import environment variables from files via imports |
| Export Environment Variables | Export task results as environment variables |
| Use Environment Variables | Use environment variables in scripts and configuration |
Declaring Environment Variables
Declare environment variables via env:
- Environment variables declared in
Pipelineare effective for the entire pipeline - Environment variables declared in
Jobare only effective for the current task
main:
push:
- docker:
# Declare build environment
image: node:22
# Environment variables declared at the pipeline level are available to all tasks in the pipeline
env:
PIPELINE_ENV_1: pipeline environment variable 1
PIPELINE_ENV_2: pipeline environment variable 2
stages:
- name: Output build environment information
script: node -v
- name: Output pipeline environment variables
script:
- echo $PIPELINE_ENV_1
- echo $PIPELINE_ENV_2
- name: Output job environment variables
# Environment variables declared in the job are only effective for the current task
env:
JOB_ENV: job environment variable
script: echo $JOB_ENVImporting Environment Variables
Use imports to import a secrets file, injecting sensitive information into environment variables for subsequent tasks to use.
Priority Rules
When there's a conflict between env and imports keys, env takes precedence.
Example
main:
push:
- services:
- docker
# Import secrets file as environment variables
imports: https://cnb.cool/<your-repo-slug>/-/blob/main/xxx/envs.yml
stages:
- name: docker info
script: docker info
- name: docker login
# Where TEST_DOCKER_DOMAIN, TEST_DOCKER_USER, TEST_DOCKER_PWD are variables from the secrets file
script: docker login $TEST_DOCKER_DOMAIN -u $TEST_DOCKER_USER -p $TEST_DOCKER_PWDenvs.yml content example:
# Docker registry domain
TEST_DOCKER_DOMAIN: registry.example.com
# Docker username
TEST_DOCKER_USER: your_docker_username
# Docker password
TEST_DOCKER_PWD: your_docker_passwordExporting Environment Variables
After a Job completes execution, there is a result object. You can use exports to export properties from result to environment variables, with a lifecycle of the current Pipeline.
Syntax Format
exports:
from-key: to-keyParameter Description:
| Parameter | Description |
|---|---|
| from-key | Property name from the Job result object to export, supports environment variables, supports deep property access, similar to lodash.get |
| to-key | Variable name to map to in environment variables |
Result Setting Methods
There are three ways to set result:
| Method | Description |
|---|---|
| Script task execution results | Output results after script execution completes |
| Parse custom variables from output | Output variables through special format |
| Built-in task results | Result objects returned by built-in tasks |
Script Task Execution Results
After a script custom script task executes, the Job result properties are:
| Property | Description |
|---|---|
| code | Return code |
| stdout | Standard output |
| stderr | Standard error |
| info | Mixed standard output and standard error in chronological order |
Output Tips
You can use printf "%s" "hello\nworld" to output variables, which removes trailing newlines from standard output while preserving escape characters like \n.
Example:
main:
push:
- stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
code: CUSTOM_ENV_DATE_CODE
info: CUSTOM_ENV_DATE_INFO
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFOProperties with Conditional Logic:
When containing if, ifModify, ifNewBranch and other conditional logic, the properties that can be set are:
| Property | Description |
|---|---|
| skip | If the task execution is skipped after the above conditional logic is evaluated, returns the skip reason, otherwise empty string |
- name: use if
if: exit -1
exports:
skip: REASON
- name: tell last
# $REASON value is the string "if"
script: echo $REASONParsing Custom Variables from Output
CI will recognize content in the format ##[set-output key=value] line by line from the standard output stream and automatically put it into the result object.
Variable Value Encoding
If the variable value contains newline \n, you can encode the variable value with base64 or escape:
| Encoding Method | Description |
|---|---|
| base64 | Variable value starts with base64,, the system will decode the content after it as base64 |
| escape | The system will unescape the variable value |
Node.js Example:
// test.js
const value = 'Test string\ntest string';
// Output base64 encoded variable value
console.log(`##[set-output redline_msg_base64=base64,${Buffer.from(value, 'utf-8').toString('base64')}]`);
// Output escape encoded variable value
console.log(`##[set-output redline_msg_escape=${escape(value)}]`)main:
push:
- docker:
image: node:20-alpine
stages:
- name: set output env
script: node test.js
# Export variables output by test.js as environment variables
exports:
redline_msg_base64: BASE64_KEY
redline_msg_escape: ESCAPE_KEY
- name: echo env
script:
- echo "BASE64_KEY $BASE64_KEY"
- echo "ESCAPE_KEY $ESCAPE_KEY"echo Example:
main:
push:
- stages:
- name: set output env
script: echo "##[set-output redline_msg_base64=base64,$(echo -e "Test string\ntest string" | base64 -w 0)]"
exports:
redline_msg_base64: BASE64_KEY
- name: echo env
script:
- echo -e "BASE64_KEY $BASE64_KEY"Note
In Unix-like systems, the base64 command adds a newline every 76 characters by default. You can use the -w 0 option to disable newlines to avoid CI failing to parse variables by line.
Variable values without \n can be output directly:
echo "##[set-output redline_msg=some value]"Limitations
- Due to system environment variable length limits, excessively large variable values are invalid
- CI will ignore variable values >=
100KB, you can write to files and parse them yourself - For sensitive information, it's recommended to use the read-file built-in task
Exporting Environment Variables from Built-in Tasks
Some built-in tasks have output results that can be exported as environment variables via exports.
main:
push:
- stages:
- name: xxxx
type: xxx:xxx
options:
product: public
name: cnb
dist: release/
exports:
version: CUSTOM_ENV_VERSION
url: CUSTOM_ENV_URL
# Supports deep object property access
nextRelease.gitTag: CUSTOM_ENV_GIT_TAG
- name: echo env
script:
- echo $CUSTOM_ENV_VERSION
- echo $CUSTOM_ENV_URLRefer to each built-in task's documentation for result content.
Managing Environment Variables
You can override existing environment variables. Setting to empty string or null deletes them.
main:
push:
- env:
CUSTOM_ENV_DATE_INFO: default
CUSTOM_ENV_FOR_DELETE: default
stages:
- name: set env
script: echo -n $(date "+%Y-%m-%d %H:%M")
exports:
# Add new
code: CUSTOM_ENV_DATE_CODE
# Modify
info: CUSTOM_ENV_DATE_INFO
# Delete
CUSTOM_ENV_FOR_DELETE: null
# Alternative delete syntax
# CUSTOM_ENV_FOR_DELETE:
- name: echo env
script:
- echo $CUSTOM_ENV_DATE_CODE
- echo $CUSTOM_ENV_DATE_INFO
- echo $CUSTOM_ENV_DATE_STDOUT
- echo $CUSTOM_ENV_FOR_DELETE
- echo $CUSTOM_ENV_GIT_TAGUsing Environment Variables
In Script Tasks
When executing script tasks, pipeline environment variables are available as task execution environment variables.
main:
push:
- stages:
- name: test internal env
# CNB_BRANCH is a built-in environment variable
script: echo $CNB_BRANCH
- name: test self defined env
env:
cat_name: tomcat
script: echo $cat_nameVariable Substitution
Some property values in configuration files will undergo variable substitution.
Substitution Rules: If there's an environment variable env_name=env_value, then $env_name in property values will be replaced with env_value. If env_name has no value, it will be replaced with an empty string.
Properties Supporting Variable Substitution
| Property | Description |
|---|---|
| Built-in task options | Property values in built-in task options and optionsFrom will undergo variable substitution |
| Plugin task settings | Property values in plugin task settings and settingsFrom will undergo variable substitution |
| env | Property values declared under env can reference variables from parent env for substitution |
| imports | Property values in imports and in declared files will undergo variable substitution |
| pipeline.runner.tags | Build node tags support variable substitution |
| pipeline.docker | volumes, image and build support variable substitution |
| stage.image and job.image | Environment image configuration supports variable substitution |
| ifModify | File change conditions support variable substitution |
| name | pipeline.name, stage.name and job.name support variable substitution |
| lock.key | Lock key name supports variable substitution |
| allowFailure | Allow failure configuration supports variable substitution |
Built-in Task Example
# options.yml
name: Nightlymain:
push:
- env:
address: options.yml
description: publish for xx task
stages:
- name: git release
type: git:release
# $address will be replaced with "options.yml" from env
optionsFrom: $address
# name from options.yml will be merged into options
options:
# $description will be replaced with "publish for xx task" from env
description: $descriptionFinal options content:
name: Nightly
description: publish for xx taskPlugin Task Example
# settings.yml
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxmain:
push:
- env:
address: settings.yml
message: pr check
stages:
- name: notify
image: tencentcom/wecom-message
# $address will be replaced with "settings.yml" from env
settingsFrom: $address
# robot from settings.yml will be merged into settings
settings:
# $message will be replaced with "pr check" from env
content: $messageFinal settings content:
robot: https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxx
message: pr checksettingsFrom in Dockerfile
settingsFrom specified in Dockerfile LABEL also supports variable substitution:
FROM node:20
LABEL cnb.cool/settings-from="$address"env Example
Property values declared under env can reference variables from parent env for substitution:
main:
push:
- env:
cat_name: tomcat
stages:
- name: echo env
env:
# Use cat_name value declared in parent env for substitution
name: "cat $cat_name"
# Outputs cat tomcat
script: echo $nameimports Example
Property values in imports and in declared files will undergo variable substitution. If imports is an array, variables declared in earlier files are effective for later array elements.
# env1.yml
address: env2.yml
platform: amd64# env2.yml
# Read platform property value from env1.yml for substitution
action: build for $platformmain:
push:
- imports:
- env1.yml
# env1.yml declared address, $address will be replaced with env2.yml
- $address
stages:
- name: echo action
# Read action property value from env2.yml for substitution
script: echo $actionpipeline.runner.tags Example
# Build images for different architectures
.build: &build
runner:
tags: cnb:arch:$CNB_PIPELINE_NAME
services:
- docker
stages:
- name: docker build
script: echo "docker build for $CNB_PIPELINE_NAME"
main:
push:
# "amd64" and "arm64:v8" below will be declared as values of built-in environment variable CNB_PIPELINE_NAME
amd64: *build
"arm64:v8": *buildpipeline.docker Example
.docker-volume: &docker-volume
docker:
# Choose either image or build
image: $image
build: $build
volumes:
- $volume_path
main:
push:
install:
env:
volume_path: node_modules
# image has no value, will use build to create an image
# image: node:22-alpine
build: Dockerfile
<<: *docker-volume
stages:
- name: install
script: npm install axios
# Notify other pipelines to execute
- name: resolve
type: cnb:resolve
options:
key: install
build:
env:
volume_path: node_modules
image: node:22-alpine
# build has no value, will use image
# build: Dockerfile
<<: *docker-volume
stages:
# Wait for install pipeline
- name: await
type: cnb:await
options:
key: install
- name: ls
script: ls node_modulesifModify Example
# Only compile corresponding module when code under different modules has changes
.build: &build
ifModify: $CNB_PIPELINE_NAME/*
stages:
- name: build $CNB_PIPELINE_NAME
script: echo "build $CNB_PIPELINE_NAME"
main:
push:
module-a: *build
module-b: *buildname Example
Property values of pipeline.name, stage.name and job.name will undergo variable substitution:
main:
push:
- name: build in $CNB_REPO_SLUG
env:
platform: amd64
imports:
- env1.yml
- env2.yml
stages:
- name: stage_$SOME_ENV
script: echo "hello world"lock.key Example
# env.yml
build_key: build key.build: &build
imports: env.yml
lock:
key: $build_key
stages:
- name: echo
script: echo "hello world"
main:
push:
# Of these two pipelines, one acquires the lock and executes successfully, the other fails to acquire the lock
- *build
- *buildallowFailure Example
main:
push:
- env:
allow_fail: true
stages:
- name: echo
allowFailure: $allow_fail
# Script execution will error, but allowFailure is true, task is considered successful
script: echo1 1Preventing Variable Substitution
If you don't want $env_name to be replaced, you can prevent substitution via \$:
main:
push:
- stages:
- name: git release
type: git:release
options:
name: Development
# Property value is "some code update $description"
description: some code update \$descriptionLimitations
Environment variables have the following limitations:
| Limitation Item | Description |
|---|---|
| Variable name format | Can only contain letters (upper/lower case), numbers and underscore (_) characters, and cannot start with a number |
| Variable value length | Cannot exceed 100KiB |
Note
Variables that don't meet the above rules will be ignored.