为什么 GitLab CI/CD downstream pipeline 的 SF_ENV input 无法使用变量?
SF_ENV 报错,是因为 GitLab 在校验 input 的 options 时,收到的仍是字符串 $SF_ENV,而允许列表中只有 dev、qual 等实际值。
DOCKER_IMAGE 能继续使用,也不能说明它在传入 input 时已经展开。这个 input 没有 options 限制,字符串 $DOCKER_IMAGE 可以通过校验;插入 image 后,还可以由后续的变量展开机制处理。
原配置中的 workflow:rules:variables 还有规则顺序和变量比较语法两个问题,需要分别修正。
为什么 job 中能读取变量,input 却校验失败?
两处处理发生在不同阶段:
$[[ inputs.SF_ENV ]]用于生成 CI/CD 配置,input 在配置处理阶段接受校验。script中的$SF_ENV由 job 的 shell 在执行时读取。
default-pipeline 输出 dev,说明该 job 的运行环境中存在 SF_ENV=dev,但不能据此判断 input 校验时是否已经得到 dev。inputs 使用 CI/CD 变量时,受到与 include 相同的变量可用性限制。参考:CI/CD inputs
当前两个 input 的校验条件不同:
inputs:
DOCKER_IMAGE: "$DOCKER_IMAGE" # 是字符串,可以通过 string 类型校验
SF_ENV: "$SF_ENV" # 不等于 options 中的任何一个值
保留 options 时,传入明确的环境值
先在触发配置中填入实际值,排除变量展开的影响:
validate-merge-request:
stage: validate
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"'
trigger:
include:
- local: "ci/sf-deploy.gitlab-ci.yml"
inputs:
DOCKER_IMAGE: "sfdx-20260423"
SF_ENV: "dev"
JOB_NAME: "validate"
这里使用 child pipeline,语法为 trigger:include:inputs,inputs 应与该条目的 local 同级。参考:trigger:include:inputs
如果需要根据 MR 目标分支选择环境,同时保留 input 的允许值校验,可以分别配置触发 job,传入对应的字面量:
.validate-trigger:
stage: validate
validate-dev:
extends: .validate-trigger
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "develop"'
trigger:
include:
- local: "ci/sf-deploy.gitlab-ci.yml"
inputs:
DOCKER_IMAGE: "sfdx-20260423"
SF_ENV: "dev"
validate-qual:
extends: .validate-trigger
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "release/1.48"'
trigger:
include:
- local: "ci/sf-deploy.gitlab-ci.yml"
inputs:
DOCKER_IMAGE: "sfdx-20260423"
SF_ENV: "qual"
validate-validation:
extends: .validate-trigger
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "release/1.47"'
trigger:
include:
- local: "ci/sf-deploy.gitlab-ci.yml"
inputs:
DOCKER_IMAGE: "sfdx-20260423"
SF_ENV: "validation"
validate-staging:
extends: .validate-trigger
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
trigger:
include:
- local: "ci/sf-deploy.gitlab-ci.yml"
inputs:
DOCKER_IMAGE: "sfdx-20260423"
SF_ENV: "staging"
用这组 job 替换原来的 validate-merge-request。下游已将 JOB_NAME 的默认值设为 validate,因此可以省略它。
镜像标签也先写成实际值,方便确认传入内容。镜像版本的统一维护可以另行处理。
下游要明确使用 input 的值
定义 SF_ENV input 不会自动创建同名环境变量。原来的脚本即使有输出,也可能读到上游转发的 CI/CD 变量:
script:
- echo "$SF_ENV"
可以将 input 映射到另一个变量,让日志显示最终采用的环境值:
spec:
inputs:
SF_ENV:
description: "The SF environment to target"
type: string
options: ["dev", "qual", "staging", "validation", "production"]
DOCKER_IMAGE:
description: "The docker image name to use from JFrog"
type: string
JOB_NAME:
description: "Job to perform"
options: ["validate", "deploy"]
default: "validate"
---
stages:
- validate-merge-request
validate-$[[ inputs.SF_ENV ]]:
image: "registry.example.com/sf-ci:$[[ inputs.DOCKER_IMAGE ]]"
tags:
- aws-docker
stage: validate-merge-request
variables:
SF_ENV_FROM_INPUT: "$[[ inputs.SF_ENV ]]"
rules:
- if: '"$[[ inputs.JOB_NAME ]]" == "validate"'
environment:
name: "$[[ inputs.SF_ENV ]]"
script:
- echo "$SF_ENV_FROM_INPUT"
将 registry.example.com 替换为实际镜像仓库地址。child pipeline 使用自己的配置,上游的 default:tags 不会自动成为下游默认配置,因此这里单独声明了 Runner 标签。
workflow 中按分支设置变量,需要怎样修改?
workflow:rules:variables 可以给整条 pipeline 设置默认变量。rules 按顺序匹配,命中后就停止。
原配置开头已放行 master、develop 和 release/ 分支。对应的 pipeline 命中这些规则后,便不会再执行后面设置 SF_ENV 的规则。
比较两个变量时,应写成:
if: '$CI_COMMIT_BRANCH == $DEV_BRANCH'
右侧不要写成 "$DEV_BRANCH"。在 rules:if 表达式中,带引号的内容按字符串处理,变量比较应直接使用 $VARIABLE_1 == $VARIABLE_2。参考:CI/CD variable expressions
将环境映射规则放在前面:
variables:
SF_ENV: "dev"
DEV_BRANCH: "develop"
QUAL_BRANCH: "release/1.48"
VALIDATION_BRANCH: "release/1.47"
workflow:
rules:
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $DEV_BRANCH || $CI_COMMIT_BRANCH == $DEV_BRANCH'
variables:
SF_ENV: "dev"
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $QUAL_BRANCH || $CI_COMMIT_BRANCH == $QUAL_BRANCH'
variables:
SF_ENV: "qual"
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $VALIDATION_BRANCH || $CI_COMMIT_BRANCH == $VALIDATION_BRANCH'
variables:
SF_ENV: "validation"
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_COMMIT_BRANCH == "master"'
variables:
SF_ENV: "staging"
- if: '$CI_COMMIT_BRANCH =~ /^release\// || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^release\//'
- if: '$CI_PIPELINE_SOURCE == "schedule"'
- when: never
这份配置仍允许其他 release/ 分支和 schedule 创建 pipeline。未匹配到明确环境映射时,继续使用默认值 dev。如果不希望回退到 dev,应删除对应的放行规则,或补齐分支映射。
MR pipeline 通过 CI_MERGE_REQUEST_TARGET_BRANCH_NAME 判断目标分支,普通分支 pipeline 通过 CI_COMMIT_BRANCH 判断当前分支。匹配规则设置的 workflow 变量可供各 job 使用。不过,修正规则顺序仍无法解决当前 input 的 options 校验问题。参考:workflow:rules:variables
如果希望只维护一份分支到环境的映射
可以将 SF_ENV 作为普通 CI/CD 变量传给下游,取消它的 input 声明:
- 保留修正后的
workflow:rules:variables。 - 删除触发配置中的
inputs.SF_ENV。 - 删除下游
spec:inputs.SF_ENV。 - 下游使用固定 job 名,并通过
$SF_ENV设置环境:
validate:
image: "registry.example.com/sf-ci:$[[ inputs.DOCKER_IMAGE ]]"
stage: validate-merge-request
environment:
name: "$SF_ENV"
script:
- |
case "$SF_ENV" in
dev|qual|staging|validation|production) ;;
*) echo "Invalid SF_ENV: $SF_ENV"; exit 1 ;;
esac
- echo "$SF_ENV"
在默认转发设置下,workflow 定义的变量会通过 trigger job 传给下游。如果配置了 inherit:variables 或 trigger:forward,需要确认 SF_ENV 没有被排除。参考:workflow 变量转发
这样会将允许值检查移到 job 执行阶段。如果必须在创建 pipeline 时拒绝非法环境,就继续使用带 options 的 input,并传入明确值。
仅删除 options 会让字符串通过校验,无法解决变量展开问题。expand_vars 也受变量可用性限制,不能保证任意 YAML 变量都能展开,也无法补救已经失败的 input 校验。参考:expand_vars
备注:内容仅供参考。
