Gitlab-ci กล้วยๆ: การใช้งาน extends กำหนดค่าซ้ำ

Gitlab-ci กล้วยๆ: การใช้งาน extends กำหนดค่าซ้ำ

หากเรามีชุดคำสั่งที่ต้องใช้งานเรียกซ้ำใน Gitlab-ci เราสามารถใช้ extends เพื่อใช้ส่วนการกำหนดค่าซ้ำ ซึ่งมันมีความยืดหยุ่น และทำให้เราอ่านโค็ดง่ายขึ้นด้วย

extends นั้นรองรับการเรียกซ้ำได้หลายระดับ แต่เราควรหลีกเลี่ยงการใช้มากกว่า 3 ระดับ เนื่องจากความซับซ้อนที่เพิ่มขึ้น แต่ก็ยังสามารถใช้ได้มากถึง 11 ระดับ ซึ่งตัวอย่างต่อไปนี้จะเป็นการใช้งาน extends แบบ 2 ระดับ

.tests:
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"

.rspec:
  extends: .tests
  script: rake rspec

rspec 1:
  variables:
    RSPEC_SUITE: '1'
  extends: .rspec

rspec 2:
  variables:
    RSPEC_SUITE: '2'
  extends: .rspec

spinach:
  extends: .tests
  script: rake spinach

จากตัวอย่างข้างต้น ถ้าเราอยากกำหนดชุดคำสั่งไว้เพื่อเรียกใช้งาน ให้เราใส่ . ก่อนชื่อ แล้วจากนั้น Job ไหนที่ต้องการรียกไปใช้งานเราก็ใช้ extends เรียกชื่อนั้นๆ ออกมา มันจะทำการรวมคำสั่งต่างๆ ให้

การใช้งาน Variables ใน extends

ตัวอย่างการใช้งาน variables

.base:
  script: test
  variables:
    VAR1: base var 1

test1:
  extends: .base
  variables:
    VAR1: test1 var 1
    VAR2: test2 var 2

test2:
  extends: .base
  variables:
    VAR2: test2 var 2

test3:
  extends: .base
  variables: {}

test4:
  extends: .base
  variables: null

ผลของการรวมกันแล้ว

test1:
  script: test
  variables:
    VAR1: test1 var 1
    VAR2: test2 var 2

test2:
  script: test
  variables:
    VAR1: base var 1
    VAR2: test2 var 2

test3:
  script: test
  variables:
    VAR1: base var 1

test4:
  script: test
  variables: null

การใช้งาน extents คู่กับ includes

เรามาดูตัวอย่างการใช้งานที่รวมกับ includes กัน

จากตัวอย่างข้างล่างนี้ มีการกำหนด script ใน included.yml ไฟล์ หลังจากนั้นก็ includes เข้ามาใน .gitlab-ci.yml แล้วก็ใช้ extends เป็นตัวเรียกชุดคำสั่งเข้ามา

  • included.yml
.template:
  script:
    - echo Hello!
  • .gitlab-ci.yml
include: included.yml

useTemplate:
  image: alpine
  extends: .template

เพิ่มเติมของการรวมคำสั่ง

มันจะมีเหตุการณ์บ้างอย่างที่เรากำหนดค่าไว้แล้ว 2 ชุดคำสั่ง แล้วเราก็เอา 2 ชุดคำสั่งนั้นมา extends เข้าที่ Job เดียว ถ้าหากในชุดคำสั่งนั้นมี ข้อมูลที่ซ้ำกัน ในขั้นตอน extents มันรวมคำสั่งให้โดยยึดเอา ชุดคำสั่งล่าสุด ไว้เสมอ ดูตัวอย่าง

.only-important:
  variables:
    URL: "http://my-url.internal"
    IMPORTANT_VAR: "the details"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "stable"
  tags:
    - production
  script:
    - echo "Hello world!"

.in-docker:
  variables:
    URL: "http://docker-url.internal"
  tags:
    - docker
  image: alpine

rspec:
  variables:
    GITLAB: "is-awesome"
  extends:
    - .only-important
    - .in-docker
  script:
    - rake rspec

ผลลัพธ์ของ rspec job

rspec:
  variables:
    URL: "http://docker-url.internal"
    IMPORTANT_VAR: "the details"
    GITLAB: "is-awesome"
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
    - if: $CI_COMMIT_BRANCH == "stable"
  tags:
    - docker
  image: alpine
  script:
    - rake rspec

อธิบายเพิ่มเติมจากข้างต้น

  • variables จะถูกรวมกัน แต่ URL: "http://docker-url.internal" จะเขียนทับ URL: "http://my-url.internal"
  • tags: ['docker'] จะเขียนทับ tags: ['production']
  • script ไม่ได้ถูกรวม แต่ script: ['rake rspec'] จะเขียนทับ script: ['echo "Hello world!"']

!reference tags

เราสามารถใช้ !reference สำหรับเรียกค่าเฉพาะบ้างอันในชุดคำสั่งเราได้

จากตัวอย่างข้างล่างนี้ script และ after_script จะมีการเรียกคำสั่งจาก 2 ชุดคำสั่งที่ต่างกันเพื่อมาใช้งานใน test job

  • setup.yml
.setup:
  script:
    - echo creating environment
  • .gitlab-ci.yml
include:
  - local: setup.yml

.teardown:
  after_script:
    - echo deleting environment

test:
  script:
    - !reference [.setup, script]
    - echo running my own command
  after_script:
    - !reference [.teardown, after_script]

มาดูอีกตัวอย่าง test-vars-1 มีการดึง variables ทั้งหมดใน .vars มาใช้ แต่ขณะที่ test-vars-2 จะเรียกเฉพาะค่า variables มาใช้และทำการกำหนด MY_VAR ขึ้นมาใหม่แทน

.vars:
  variables:
    URL: "http://my-url.internal"
    IMPORTANT_VAR: "the details"

test-vars-1:
  variables: !reference [.vars, variables]
  script:
    - printenv

test-vars-2:
  variables:
    MY_VAR: !reference [.vars, variables, IMPORTANT_VAR]
  script:
    - printenv

การใช้งาน !refereance ในส่วนของ script, before_script และ after_script

เราสามารถใช้ !refereance ได้ถึง 10 ระดับใน script, before_script และ after_script แต่ก็อย่าไปใช้เยอะเลยเดียวจะสับสน ดูตัวอย่างการใช้งาน

.snippets:
  one:
    - echo "ONE!"
  two:
    - !reference [.snippets, one]
    - echo "TWO!"
  three:
    - !reference [.snippets, two]
    - echo "THREE!"

nested-references:
  script:
    - !reference [.snippets, three]

จากตัวอย่างข้างต้น nested-references job จะทำคำสั่ง echo ทั้ง 3 อัน

ตั้งค่า IDE เพื่อใข้งาน !refereance

โดยปกติ YAML จะไม่รองรับในการเขียน !refereance ซึ่งมันจะแสดง Error ออกมาในส่วนของ IDE ที่เราใช้งาน ถ้าใครใช้ vscode อยู่สามารถแก้ไขได้ดังนี้

  • แก้ไขไฟล์ settings.json file:
"yaml.customTags": [
   "!reference sequence"
]

extends จะทำให้เราสามารถเขียนไฟล์ .gitab-ci ได้สนุกมากขึ้น และเขียนในรูปแบบบ template เพื่อเรียกใช้งานซ้ำๆ ได้เลย ผมใช้ประจำ :)

Thanks:

  • https://docs.gitlab.com/ee/ci/yaml/#extends
  • https://docs.gitlab.com/ee/ci/yaml/yaml_optimization.html#use-extends-to-reuse-configuration-sections

Arnon Kijlerdphon

Arnon Kijlerdphon

Board game & Plant-based & Minimalist, it's all my life.
Bangkok, Thailand