如何使用YAML锚点避免CI脚本代码段重复?
解决GitLab CI重复作业的YAML锚点正确用法
问题场景
你有多个结构相似的CI作业,仅tags和脚本中的部分变量值不同,示例代码如下:
test a: stage: test tags: - a interruptible: true rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' script: - echo "env is $(env)" - echo etcetera - echo and so on - docker build -t a -f Dockerfile.a . test b: stage: test tags: - b interruptible: true rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' script: - echo "env is $(env)" - echo etcetera - echo and so on - docker build -t b -f Dockerfile.b .
尝试用锚点统一脚本时遇到两种问题:
- 直接定义脚本列表锚点,在作业中用
<<: *which_ref会触发YAMLException: cannot merge mappings; the provided source object is unacceptable错误 - 定义包含
script节点的锚点,作业中声明新的script会覆盖锚点内容
正确解决方案
方案1:复用完整作业模板(推荐)
定义包含所有重复字段的作业模板锚点,每个作业通过继承模板并覆盖差异字段(如tags)、设置专属变量来实现复用:
# 定义通用作业模板锚点 .job_template: &job_template stage: test interruptible: true rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' script: - echo "env is $(env)" - echo etcetera - echo and so on - docker build -t $WHICH -f Dockerfile.$WHICH . # 作业a:继承模板+覆盖差异 test a: <<: *job_template tags: - a variables: WHICH: a # 作业b:继承模板+覆盖差异 test b: <<: *job_template tags: - b variables: WHICH: b
这种方式直接复用整个作业的重复配置,仅需修改每个作业独有的tags和WHICH变量,完全避免重复代码。
方案2:仅复用脚本列表
如果只需要复用script部分的代码,可单独定义脚本列表锚点,在作业的script列表中直接引用锚点即可(注意不要用映射合并语法<<:):
# 定义通用脚本列表锚点 .script_template: &script_template - echo "env is $(env)" - echo etcetera - echo and so on - docker build -t $WHICH -f Dockerfile.$WHICH . test a: stage: test tags: - a interruptible: true rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' variables: WHICH: a script: # 可添加作业专属前置步骤 - echo "Starting job a" # 引用通用脚本列表 - *script_template test b: stage: test tags: - b interruptible: true rules: - if: $CI_PIPELINE_SOURCE == 'merge_request_event' variables: WHICH: b script: - *script_template
错误原因说明
- 第一种错误:
<<:是YAML中**合并映射(键值对结构)**的语法,不能用于列表(数组)结构中,因此直接在script列表里用<<: *which_ref会触发语法错误。 - 第二种错误:当锚点包含
script键时,作业中重新声明script会覆盖锚点里的同名键,YAML中后定义的键会优先覆盖之前的。
内容的提问来源于stack exchange,提问作者Steven Lu
相关产品推荐
相关产品推荐

