Search code examples
gitlabcontinuous-integrationgitlab-ci

Multiple sections in "extends" these days (Gitlab)


I need to do extends of more than one section in .gitlab-ci.yml.

I have three+ "prerequisite" sections, but I don't want to use them all every time in subsequent "production" stages, so I can't combine them into one big prerequisite section.

Specifically I would like to do something like:

.prereq1:
  before_script:
    apt-get update ...
    # many other steps

.prereq2:      
  before_script:
    apt-get install package2 ...
    # many other steps

.prereq3:      
  before_script:
    apt-get install package3 ...
    # many other steps

usable_stage_A:
  stage: usable_stage_A
  only:
    # this will only be ran in pipeline schedule A
    variables:
      - "$JOB_A"
  extends:
   .prereq1
   .prereq2 

usable_stage_B:
  stage: usable_stage_B
  # this will only be ran in pipeline schedule B
  only:
    variables:
      - "$JOB_B"
  extends:
   .prereq1
   .prereq3

How can I do that?


Solution

  • extends: won't work well in this case because arrays can't be combined through this method.

    However, you can use !reference to compose the script sections.

    .install_scripts:
      prereq1:
        - apt install -y package1
      prereq2:
        - apt install -y package2
      # etc
    
    jobA:
      before_script:
        - !reference [.install_scripts, prereq1]
        - !reference [.install_scripts, prereq2]
        - echo 'more before script for jobA'
      # ...
    

    It is possible to provide an array of values to extends: to extend from multiple keys. However, only hashes are merged. Arrays or scalar values are simply overridden. Hence, because before_script: only accepts arrays or strings, it cannot be merged this way.

    Reference: yaml merge details:

    You can use extends to merge hashes but not arrays. The algorithm used for merge is “closest scope wins”. When there are duplicate keys, GitLab performs a reverse deep merge based on the keys. Keys from the last member always override anything defined on other levels.