學習目標
- 用
needs讓 job 只等它真正需要的 job,縮短整條 pipeline 的時間。 - 知道
needs也決定要下載哪些產物。 - 會用
parallel:matrix同時測多個版本。 - 會用
extends與!reference重用設定。
觀念:stage 與 DAG 的差別
只用 stage 時,test-api 要等 build-web(慢 30 秒)也做完才開始。加了 needs:
build-api(5s) ──▶ test-api ──┐
build-web(30s) ─────▶ test-web ──┴▶ package
lint(needs: [],一開始就跑)
compat: [3.12] [3.13](needs: [],一開始就跑)pipeline 頁面切到「Job dependencies」可以看到這張圖。
| 寫法 | 意思 |
|---|---|
needs: [build-api] | 只等 build-api,也只下載它的產物 |
needs: [] | 什麼都不等,pipeline 一開始就跑 |
needs: [{ job: x, artifacts: false }] | 等 x 成功,但不下載產物 |
parallel: { matrix: [...] } | 每組變數各產生一個 job,名稱像 compat: [3.12] |
重用設定
extends: .python:把隱藏 job.python整段合併進來(hash 深層合併,陣列整個取代)。!reference [.python, before_script]:只拿某一段,可以和自己的指令混在同一個陣列。
動手做
- 看 pipeline 的時間軸:
test-api在build-web還沒結束時就開始了。 - 把
test-api的needs拿掉,比較整條 pipeline 多花多久。 - 在 matrix 加上
"3.11",多出一個 job。
常見錯誤
needs指到同一個或之後階段的 job:一樣可以(同階段 needs 已支援),但不能形成循環。needs指到被rules排除的 job:pipeline 會建立失敗。可以加optional: true。- 用了
needs卻沒拿到產物:needs只下載列出的 job 的產物,其他階段的不會自動下載。
下一關
Lv.8 在 job 旁邊開資料庫:services。
範例檔案
資料夾 lv07-needs-dag/ 的全部檔案。.gitlab-ci.yml 可以直接複製到自己的專案根目錄執行。
lv07-needs-dag/.gitlab-ci.yml
lv07-needs-dag/.gitlab-ci.yml
# Lv.7 Needs 與 DAG:job 不用等整個階段,只等它真正需要的 job
# 再加上 parallel:matrix(同一個 job 用不同參數跑多份)與 extends、!reference(重用設定)。
stages:
- build
- test
- package
.python:
image: python:3.13-alpine
before_script:
- python3 --version
build-api:
stage: build
extends: .python
script:
- sleep 5
- mkdir -p out && echo "api 建置於 $(date -u +%T)" > out/api.txt
artifacts:
paths: [out/api.txt]
expire_in: 1 day
build-web:
stage: build
extends: .python
script:
- sleep 30 # 故意比較慢
- mkdir -p out && echo "web 建置於 $(date -u +%T)" > out/web.txt
artifacts:
paths: [out/web.txt]
expire_in: 1 day
test-api:
stage: test
extends: .python
# 只等 build-api:build-web 還在跑,這個 job 就已經開始了
needs: [build-api]
script:
- cat out/api.txt
- test ! -f out/web.txt && echo "needs 只下載 build-api 的產物"
test-web:
stage: test
extends: .python
needs: [build-web]
script:
- cat out/web.txt
# needs: [] = 不等任何 job,pipeline 一開始就跑
lint:
stage: test
image: alpine:3.22
needs: []
script:
- echo "風格檢查不需要建置產物,一開始就跑"
# 同一個 job 用兩個 Python 版本各跑一份
compat:
stage: test
needs: []
image: python:${PY_VERSION}-alpine
parallel:
matrix:
- PY_VERSION: ["3.12", "3.13"]
script:
- python3 -c "import sys; print('相容性測試', sys.version.split()[0])"
package:
stage: package
extends: .python
needs:
- job: test-api
artifacts: false # 只等它成功,不下載它的產物
- job: test-web
artifacts: false
- job: build-api # 要用產物的 job 才要列 artifacts: true(預設就是 true)
- job: build-web
before_script:
- !reference [.python, before_script]
- echo "!reference 可以只拿別的 job 的某一段設定"
script:
- cat out/api.txt out/web.txt
- echo "打包完成"