GitLab CI中If/Else条件分支不生效问题排查
问题
我配置了如下GitLab CI脚本,期望实现:
- 当打如
staging.v1这类staging开头的Git标签时,执行对应的staging构建与发布逻辑; - 当在develop分支打如
v1.0.1这类v开头的标签时,执行生产环境的构建与发布逻辑。
但实际条件分支未触发,无报错信息,仅显示命令折叠后直接完成任务。配置脚本如下:
include: - project: templates/gitlab-templates file: sorush.gitlab-ci.yml stages: - build - release variables: OKD_REGISTRY_BALY: "registry.apps.internal.okd.eu-central-1.cloud.baly.app" OKD_REGISTRY_BALY_STAGING: "registry.apps.internal.okd.eu-central-1.cloud.baly.app" OKD_PROJECT_BALY: baly-dpn-blitz OKD_PROJECT_BALY_STAGING: baly-dpn-blitz CONTAINER_REGISTRY_IMAGE_TAG_API_BALY: "api_baly_latest" CONTAINER_REGISTRY_IMAGE_TAG_API_BALY_STAGING: "api_baly_staging" CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE: "feature_update_baly_latest" CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE_STAGING: "feature_update_baly_staging" CONTAINER_REGISTRY_USERNAME: 'gitlab-ci' CONTAINER_REGISTRY_PASSWORD: ${OKD_BALY_TOKEN} OKD_CONSOLE_URL: https://api.okd.eu-central-1.cloud.baly.app:6443 build: stage: build image: docker:dind before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: | if [[ $CI_COMMIT_TAG =~ ^staging.*$ ]]; then echo "Building staging...." docker build -t ${CI_REGISTRY_IMAGE}:api_baly_staging_${CI_COMMIT_REF_SLUG} --file api_baly_dockerfile.dockerfile . docker build -t ${CI_REGISTRY_IMAGE}:feature_update_baly_staging_${CI_COMMIT_REF_SLUG} --file api_baly_dockerfile.dockerfile . docker push ${CI_REGISTRY_IMAGE}:api_baly_staging_${CI_COMMIT_REF_SLUG} docker push ${CI_REGISTRY_IMAGE}:feature_update_baly_staging_${CI_COMMIT_REF_SLUG} elif [[ $CI_COMMIT_TAG =~ ^v.*$ && "$CI_COMMIT_BRANCH" == "develop" ]]; then echo "Building production...." docker build -t ${CI_REGISTRY_IMAGE}:api_baly_${CI_COMMIT_REF_SLUG} --file api_baly_dockerfile.dockerfile . docker build -t ${CI_REGISTRY_IMAGE}:feature_update_baly_${CI_COMMIT_REF_SLUG} --file api_baly_dockerfile.dockerfile . docker push ${CI_REGISTRY_IMAGE}:api_baly_${CI_COMMIT_REF_SLUG} docker push ${CI_REGISTRY_IMAGE}:feature_update_baly_${CI_COMMIT_REF_SLUG} fi rules: - if: '$CI_COMMIT_TAG =~ /staging.*$/' when: always - if: '$CI_COMMIT_TAG =~ /v.*$/' when: always .release-cloud: &release-cloud rules: - if: '$CI_COMMIT_TAG =~ /staging.*$/' when: always - if: '$CI_COMMIT_TAG =~ /v.*$/' when: always image: docker:dind stage: release before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - if [[ "$CI_COMMIT_TAG" =~ ^staging.*$ ]]; then docker pull ${CI_REGISTRY_IMAGE}:api_baly_staging_${CI_COMMIT_REF_SLUG}; docker pull ${CI_REGISTRY_IMAGE}:feature_update_baly_staging_${CI_COMMIT_REF_SLUG}; fi - if [[ "$CI_COMMIT_TAG" =~ ^v.*$ ]]; then docker pull ${CI_REGISTRY_IMAGE}:api_baly_${CI_COMMIT_REF_SLUG}; docker pull ${CI_REGISTRY_IMAGE}:feature_update_baly_${CI_COMMIT_REF_SLUG}; fi - docker logout $CI_REGISTRY script: | if [[ $CI_COMMIT_TAG =~ ^staging.*$ ]]; then docker login -u ${CONTAINER_REGISTRY_USERNAME} -p ${CONTAINER_REGISTRY_PASSWORD} ${OKD_REGISTRY} docker tag ${CI_REGISTRY_IMAGE}:api_baly_staging_${CI_COMMIT_REF_SLUG} ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_API_BALY_STAGING} docker tag ${CI_REGISTRY_IMAGE}:feature_update_baly_staging_${CI_COMMIT_REF_SLUG} ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE_STAGING} docker push ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_API_BALY_STAGING} docker push ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE_STAGING} elif [[ $CI_COMMIT_TAG =~ ^v.*$ && "$CI_COMMIT_BRANCH" == "develop" ]]; then docker login -u ${CONTAINER_REGISTRY_USERNAME} -p ${CONTAINER_REGISTRY_PASSWORD} ${OKD_REGISTRY} docker tag ${CI_REGISTRY_IMAGE}:api_baly_${CI_COMMIT_REF_SLUG} ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_API_BALY} docker tag ${CI_REGISTRY_IMAGE}:feature_update_baly${CI_COMMIT_REF_SLUG} ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE} docker push ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_API_BALY} docker push ${CONTAINER_REGISTRY_IMAGE}:${CONTAINER_REGISTRY_IMAGE_TAG_FEATURE_BALY_UPDATE} fi Release (baly): variables: DOCKER_DRIVER: overlay2 CONTAINER_REGISTRY_PASSWORD: ${OKD_BALY_TOKEN} OKD_REGISTRY: ${OKD_REGISTRY_BALY} CONTAINER_REGISTRY_IMAGE: "$OKD_REGISTRY_BALY/$OKD_PROJECT_BALY/$CI_PROJECT_NAME" <<: *release-cloud
执行日志显示:
Login Succeeded
$ if [[ $CI_COMMIT_TAG =~ ^staging.*$ ]]; then # collapsed multi-line command
Cleaning up project directory and file based variables 00:01
Job succeeded
问题排查与修复方案
1. 标签流水线中CI_COMMIT_BRANCH变量为空
GitLab在标签触发的流水线中不会设置CI_COMMIT_BRANCH变量,你脚本中用"$CI_COMMIT_BRANCH" == "develop"判断生产分支的逻辑永远不成立,导致生产构建/发布代码块从未执行。
修复:
改用Git命令检查当前标签对应的提交是否属于develop分支:
elif [[ $CI_COMMIT_TAG =~ ^v.*$ ]]; then # 检查标签关联的提交是否在develop分支上 if git branch --contains $CI_COMMIT_SHA | grep -q develop; then echo "Building production...." # 原生产构建逻辑 fi
2. 正则匹配规则不精准
你在rules中使用的正则/staging.*$/和/v.*$/没有限制开头匹配,可能导致意外匹配。同时生产标签的rules没有限制分支,会触发不必要的流水线。
修复:
更新build和.release-cloud的rules,使用更精准的正则:
# build阶段rules修改 rules: - if: '$CI_COMMIT_TAG =~ /^staging\..+$/' when: always - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/' when: always # .release-cloud的rules同步修改 rules: - if: '$CI_COMMIT_TAG =~ /^staging\..+$/' when: always - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/' when: always
3. 镜像标签拼接错误
release阶段生产逻辑中,镜像标签少了下划线:
docker tag ${CI_REGISTRY_IMAGE}:feature_update_baly${CI_COMMIT_REF_SLUG} ...
应该改为feature_update_baly_${CI_COMMIT_REF_SLUG},和build阶段的镜像标签保持一致,否则会找不到镜像导致命令静默失败。
4. 缺少错误检查与日志输出
当前脚本没有错误终止机制,命令失败后会继续执行,且折叠命令无法看到具体错误。
修复:
在脚本开头添加set -euo pipefail,让脚本在命令失败时立即终止;同时展开折叠命令或增加关键步骤的日志输出:
script: | set -euo pipefail if [[ $CI_COMMIT_TAG =~ ^staging.*$ ]]; then echo "Starting staging release..." # 后续逻辑 fi
5. 环境变量未区分环境
当前staging和生产的OKD_REGISTRY_BALY、OKD_PROJECT_BALY变量值完全相同,会导致两个环境发布到同一地址,需确认是否是配置失误。如果需要区分,可在release阶段根据标签类型动态设置变量:
Release (baly): variables: DOCKER_DRIVER: overlay2 CONTAINER_REGISTRY_PASSWORD: ${OKD_BALY_TOKEN} <<: *release-cloud rules: - if: '$CI_COMMIT_TAG =~ /^staging\..+$/' variables: OKD_REGISTRY: ${OKD_REGISTRY_BALY_STAGING} CONTAINER_REGISTRY_IMAGE: "$OKD_REGISTRY_BALY_STAGING/$OKD_PROJECT_BALY_STAGING/$CI_PROJECT_NAME" - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/' variables: OKD_REGISTRY: ${OKD_REGISTRY_BALY} CONTAINER_REGISTRY_IMAGE: "$OKD_REGISTRY_BALY/$OKD_PROJECT_BALY/$CI_PROJECT_NAME"
内容的提问来源于stack exchange,提问作者MarziehSepehr

