Search code examples
bashcontinuous-integrationgitlabgitlab-ci-runner

Having Gitlab Projects calling the same gitlab-ci.yml stored in a central location


I have many Gitlab project followed the same CI template. Whenever there is a small change in the CI script, I have to manually modify the CI script in each project. Is there a way you can store your CI script in a central location and have your project called that CI script with some environment variable substitution? For instance,

gitlab-ci.yml in each project

/bin/bash -c "$(curl -fsSL <link_to_the_central_location>.sh)"

gitlab-ci.yml in the central location

stages:
  - build
  - test

build-code-job:
  stage: build
  script:
    - echo "Check the ruby version, then build some Ruby project files:"
    - ruby -v
    - rake

test-code-job1:
  stage: test
  script:
    - echo "If the files are built successfully, test some files with one command:"
    - rake test1

test-code-job2:
  stage: test
  script:
    - echo "If the files are built successfully, test other files with a different command:"
    - rake test2

Solution

  • You do not need curl, actually gitlab supports this via the include directive.

    1. you need a repository, where you store your general yml files. (you can choose if it is a whole ci file, or just parts. For this example lets call this repository CI and assume your gitlab runs at example.com - so the project url would be example.com/ci. we create two files in there just to show the possibilities.

      1. is a whole CI definition, ready to use - lets call the file ci.yml. This approach is not really flexible

         stages:
           - build
           - test
        
         build-code-job:
           stage: build
           script:
             - echo "Check the ruby version, then build some Ruby project files:"
             - ruby -v
             - rake
        
         test-code-job1:
           stage: test
           script:
             - echo "If the files are built successfully, test some files with one command:"
             - rake test1
        
         test-code-job2:
           stage: test
           script:
             - echo "If the files are built successfully, test other files with a different command:"
             - rake test2
        
      2. is a partly CI definition, which is more extendable. lets call the files includes.yml

         .build:
           stage: build
           script:
             - echo "Check the ruby version, then build some Ruby project files:"
             - ruby -v
             - rake
        
         .test:
           stage: test
           script:
             - echo "this script tag will be overwritten"
        
      3. There is even the option to use template string from yaml. please reference the gitlab documentation but it is similar to 2.

    2. we do have our project which wants to use such definitions. so either

      1. For the whole CI file

         include:
           - project: 'ci'
             ref: master # think about tagging if you need it
             file: 'ci.yml'
        

        as you can see now we are referencing one yml file, with all the cahnges.

      2. with partial extends

         include:
           - project: 'ci'
             ref: master # think about tagging if you need it
             file: 'includes.yml'
        
         stages:
           - build
           - test
        
         build-code-job:
           extends: .build
        
         job1:
           extends: .test
           script:
             - rake test1
        
         job2:
           extends: .test
           script:
             - rake test2
        

        As you see, you can easily use the includes, to have a way more granular setup. Additionally you could define at job1 and job2 variables, eg for the test target, and move the script block into the includes.yml

    Futhermore you can also use anchors for the script parts. Which looks like this

    includes.yml

    .build-scirpt: &build
         - echo "Check the ruby version, then build some Ruby project files:"
         - ruby -v
         - rake
    
    .build:
       stage: build
       script:
         - *build
    

    and you can use also the script anchor within your configuration

    For a deeper explanation you can also take a look at https://docs.gitlab.com/ee/ci/yaml/includes.html