目錄
- GitLab CI流水線配置文件.gitlab-ci.yml詳解
- 實驗環境
- GitLab CI介紹
.gitlab-ci.yml
配置參數- 參數詳解
script
image
services
before_script
after_script
stages
stage
only
和except
only
和except
高級用法only
和except
綜合示例tags
allow_failure
when
environment
cache
artifacts
dependencies
coverage
retry
trigger
include
extends
pages
variables
- 廢棄的關鍵字
types
和type
- 使用
GIT_CLONE_PATH
自定義構建目錄 - 特殊的YAML功能
- Triggers觸發器
- 忽略CI檢查
本文講解在 GitLab的漢化與CI持續集成gitlab-runner的配置 的基礎上,對GitLab CI流水線配置文件 .gitlab-ci.yml
進行詳細的介紹。
實驗環境
- server服務端: 操作系統為CentOS 7.6,IP:192.168.56.14, git:2.16.5。
查看server服務端信息:
[root@server ~]# cat /etc/centos-release CentOS Linux release 7.6.1810 (Core) [root@server ~]# ip a show|grep 192 inet 192.168.56.14/24 brd 192.168.56.255 scope global noprefixroute enp0s3 [root@server ~]# git --version git version 2.16.5
GitLab用戶信息:
賬號 密碼 root 1234567890 meizhaohui 1234567890
GitLab WEB網站地址: http://192.168.56.14
之前我們配置的 bluelog
的4#流水線已經 已通過 了:

可以發現其 build
、Test
、Deploy
三個階段的任務都執行成功!
而流水線執行的具體過程都是由 .gitlab-ci.yml
配置文件定義的,本文詳細講解 .gitlab-ci.yml
配置文件的使用。
GitLab CI介紹
- GitLab提交持續集成服務,當你在項目根目錄中添加
.gitlab-ci.yml
文件,並配置項目的運行器(GitLab Runner
),那么后續的每次提交都會觸發CI流水線(pipeline
)的執行。 .gitlab-ci.yml
文件告訴運行器需要做哪些事情,默認情況下,流水線有build
、test
、deploy
三個階段,即構建
、測試
、部署
,未被使用的階段將會被自動忽略。- 如果一切運行正常(沒有非零返回值),您將獲得與提交相關聯的漂亮綠色復選標記(如下圖所示)。這樣可以在查看代碼之前輕松查看提交是否導致任何測試失敗。

- 大多數項目使用GitLab的CI服務來運行測試套件,以便開發人員在破壞某些內容時可以立即獲得反饋。使用持續交付和持續部署將測試代碼自動部署到模擬環境和生產環境的趨勢越來越明顯。
- 由於將
.gitlab-ci.yml
文件存放在倉庫中進行版本控制,使用單一的配置文件來控制流水線,具有讀訪問權限的每個人都可以查看內容,從而使其更有吸引力地改進和查看構建腳本。舊的版本也能構建成功,forks項目也容易使用CI,分支可以有不同的流水線和作業。 .gitlab-ci.yml
定義每個項目的流水線的結構和順序,由以下兩個因素決定:
- GiTlab Runner運行器使用的執行器(
executor
),執行器常用的Shell
、Docker
、Kubernets
, 我們當前僅使用Shell
執行器,后續再使用其他執行器。- 遇到進程成功或失敗時等條件時做出的決定。
- 可以在 Getting started with GitLab CI/CD 查看到流水線的簡單示例。
- 可以在 GitLab CI/CD Examples 查看更多的流水線示例。
- 在流水線腳本中可以使用預定義的全局變量,詳細可查看 GitLab CI/CD Variables 。
- 企業級的
.gitlab-ci.yml
示例可查看 https://gitlab.com/gitlab-org/gitlab-ce/blob/master/.gitlab-ci.yml 。 - Job作業是
.gitlab-ci.yml
文件的基本元素,每個作業至少有script
子句,在流水線中可以定義任意多個作業。 - 每個作業必須具有唯一的名稱,但有一些保留的關鍵字不能用作作業名稱,保留關鍵字(
reserved keywords
)有image
、services
、stages
、types
、before_script
、after_script
、variables
、cache
。
.gitlab-ci.yml
配置參數
關鍵字 | 描述 |
script | 必須參數,運行器需要執行的腳本 |
image | 使用Docker image鏡像 |
services | 使用Docker services鏡像 |
before_script | 作業執行前需要執行的命令 |
after_script | 作業執行后需要執行的命令 |
stages | 定義流水線所有的階段 |
stage | 定義作業所處流水線的階段(默認test階段) |
only | 限制作業在什么時候創建 |
except | 限制作業在什么時候不創建 |
tags | 作用使用的Runner運行器的標簽列表 |
allow_failure | 允許作業失敗,失敗的作業不影響提交的狀態 |
when | 什么時候運行作業 |
environment | 作用部署的環境名稱 |
cache | 指定需要在job之間緩存的文件或目錄 |
artifacts | 歸檔文件列表,指定成功后應附加到job的文件和目錄的列表 |
dependencies | 當前作業依賴的其他作業,你可以使用依賴作業的歸檔文件 |
coverage | 作業的代碼覆蓋率 |
retry | 作業失敗時,可以自動執行多少次 |
parallel | 指定並行運行的作業實例 |
trigger | 定義下游流水線的觸發器 |
include | 作業加載其他YAML文件 |
extends | 控制實體從哪里繼承 |
pages | 上傳GitLab Pages的結果 |
retry | 作業失敗時,可以自動執行多少次 |
variables | 定義環境變量 |
參數詳解
script
script
是作業中唯一必須的關鍵字參數,是運行器需要執行的腳本,如:
build1: script: - echo "Do your build here" - uname -a
表示build1作業需要執行的命令是輸出”Do your build here”。
Warning
Sometimes, script commands will need to be wrapped in single or double quotes. For example, commands that contain a colon (:) need to be wrapped in quotes so that the YAML parser knows to interpret the whole thing as a string rather than a “key: value” pair. Be careful when using special characters: :, {, }, [, ], ,, &, *, #, ?, |, -, <, >, =, !, %, @, `. 即使用冒號時應使用引號包裹起來,使用特殊字符時需要特別注意!!!注意如果要輸出冒號字符,冒號后面不能緊接空格!!!
image
image
指定使用Docker鏡像。如 iamge:name
,暫時忽略。
services
services
指定使用Docker鏡像服務。如 services:name
,暫時忽略。
before_script
before_script
用於定義在所有作業之前需要執行的命令,比如更新代碼、安裝依賴、打印調試信息之類的事情。
示例:
before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details"
after_script
after_script
用於定義在所有作業(即使失敗)之后需要執行的命令,比如清空工作空間。
示例:
after_script: - echo "After script section" - echo "For example you might do some cleanup here"
Important
-
before_script和script在一個上下文中是串行執行的,after_script是獨立執行的,即after_script與before_script/script的上下文環境不同。
-
after_script會將當前工作目錄設置為默認值。
-
由於after_script是分離的上下文,在after_script中無法看到在before_script和script中所做的修改:
- 在before_script和script中的命名別名、導出變量,對after_script不可見;
- before_script和script在工作樹之外安裝的軟件,對after_script不可見。
-
你可以在作業中定義before_script,after_script,也可以將其定義為頂級元素,定義為頂級元素將為每一個任務都執行相應階段的腳本或命令。作業級會覆蓋全局級的定義。
示例:
before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version - cloc . script: - echo "Do your build here" - cloc --version - cloc . tags: - bluelog
將修改上傳提交,查看作業build1的控制台輸出:


可以發現build1作業的 before_script
和 after_script
將全局的 before_script
和 after_script
覆蓋了。
stages
stages
定義流水線全局可使用的階段,階段允許有靈活的多級管道,階段元素的排序定義了作業執行的順序。
- 相同
stage
階段的作業並行運行。 - 默認情況下,上一階段的作業全部運行成功后才執行下一階段的作業。
- 默認有三個階段,
build
、test
、deploy
三個階段,即構建
、測試
、部署
。 - 如果一個作業未定義
stage
階段,則作業使用test
測試階段。 - 默認情況下,任何一個前置的作業失敗了,commit提交會標記為failed並且下一個stages的作業都不會執行。
stage
stage
定義流水線中每個作業所處的階段,處於相同階段的作業並行執行。
示例:
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version - cloc . script: - echo "Do your build here" - cloc --version - cloc . tags: - bluelog find Bugs: stage: code_check script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version - flake8 . tags: - bluelog test1: stage: test script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog
我們增加一個 code_check
階段,該階段有一個作業 find Bugs
,該作業主要是先安裝Flake8,然后使用Flake8對Python代碼進行規范檢查。

由於Flake8檢查到了Python代碼中的缺陷,導致find Bugs作業失敗!這樣可以控制開發人員提交有壞味道的代碼到倉庫中。
另外,在上一個流水線中,Test階段的作業test1和test2是並行執行的,如下圖所示:

本次(pipeline #7)流水線由於在作業 find Bugs
檢查不通過,導致整個流水線運行失敗,后續的作業不會執行:

Attention
默認情況下,GitLab Runner運行器每次只執行一個作業,只有當滿足以下條件之一時,才會真正的並行執行:
- 作業運行在不同的運行器上;
- 你修改了運行器的
concurrent
設置,默認情況下concurrent = 1
。
only
和 except
only
和 except
用於在創建作業時對作業的限制策略。
only
定義了哪些分支或標簽(branches and tags)的作業會運行except
定義了哪些分支或標簽(branches and tags)的作業不會運行
下面是策略規則:
only
和except
可同時使用,如果在一個作業中同時定義了only
和except
,則同時only
except
進行過濾(注意,不是忽略except
條件) 。only
和except
可以使用正則表達式。only
和except
允許指定用於過濾forks作業的存儲庫路徑。only
和except
中可以使用特殊的關鍵字,如branches
、tags
、api
、external
、pipelines
、pushes
、schedules
、triggers
、web
、merge_requests
、chats
等。
only
和 except
中可以使用特殊的關鍵字:
關鍵字 | 描述釋義 |
branches | 當一個分支被push上來 |
tags | 當一個打了tag標記的Release被提交時 |
api | 當一個pipline被第二個piplines api所觸發調起(不是觸發器API) |
external | 當使用了GitLab以外的外部CI服務,如Jenkins |
pipelines | 針對多項目觸發器而言,當使用CI_JOB_TOKEN, 並使用gitlab所提供的api創建多個pipelines的時候 |
pushes | 當pipeline被用戶的git push操作所觸發的時候 |
schedules | 針對預定好的pipline計划而言(每日構建一類) |
triggers | 用觸發器token創建piplines的時候 |
web | 在GitLab WEB頁面上Pipelines標簽頁下,按下run pipline的時候 |
merge_requests | 當合並請求創建或更新的時候 |
chats | 當使用GitLab ChatOps 創建作業的時候 |
在下面這個例子中,job將只會運行以 issue-
開始的refs(分支),然而except中指定分支不能執行,所以這個job將不會執行:
job:
# use regexp
only:
- /^issue-.*$/
# use special keyword
except:
- branches
匹配模式默認是大小寫敏感的(case-sensitive),使用 i
標志,如 /pattern/i
可以使匹配模式大小寫不敏感:
job:
# use regexp
only:
- /^issue-.*$/i
# use special keyword
except:
- branches
下面這個示例,僅當指定標記的tags的refs引用,或者通過API觸發器的構建、或者流水線計划調度的構建才會運行:
job: # use special keywords only: - tags - triggers - schedules
倉庫的路徑(repository path)只能用於父級倉庫執行作業,不能用於forks:
job:
only:
- branches@gitlab-org/gitlab-ce
except:
- master@gitlab-org/gitlab-ce
- /^release/.*$/@gitlab-org/gitlab-ce
上面這個例子,將會在所有分支執行,但 不會在 master主干以及以release/開頭的分支上執行。
- 當一個作業沒有定義
only
規則時,其默認為only: ['branches', 'tags']
。 - 如果一個作業沒有定義
except
規則時,則默認except
規則為空。
下面這個兩個例子是等價的:
job: script: echo 'test'
轉換后:
job: script: echo 'test' only: ['branches', 'tags']
Attention
關於正則表達式使用的說明:
- 因為
@
用於表示ref的存儲庫路徑的開頭,所以在正則表達式中匹配包含@
字符的ref名稱需要使用十六進制字符代碼\x40
。 - 僅標簽和分支名稱才能使用正則表達式匹配,倉庫路徑按字面意義匹配。
- 如果使用正則表達式匹配標簽或分支名稱,則匹配模式的整個引用部分都是正則表達式。
- 正則表達式必須以
/
開頭和結尾,即/regular expressions/
,因此,issue-/.*/
不會匹配以issue-
開頭的標簽或分支。 - 可以在正則表達式中使用錨點
^$
,用來匹配開頭或結尾,如/^issue-.*$/
與/^issue-/
等價, 但/issue/
卻可以匹配名稱為severe-issues
的分支,所以正則表達式的使用要謹慎!
only
和 except
高級用法
only
和except
支持高級策略,refs
、variables
、changes
、kubernetes
四個關鍵字可以使用。- 如果同時使用多個關鍵字,中間的邏輯是
邏輯與AND
。
only:refs/except:refs
refs
策略可以使用only
和except
基本用法中的關鍵字。
下面這個例子中,deploy作業僅當流水線是計划作業或者在master主干運行:
deploy: only: refs: - master - schedules
only:kubernetes/except:kubernetes
kubernetes
策略僅支持active
關鍵字。
下面這個例子中,deploy作業僅當kubernetes服務啟動后才會運行:
deploy: only: kubernetes: active
only:variables/except:variables
variables
關鍵字用來定義變量表達式,你可以使用預定義變量、項目、組、環境變量來評估一個作業是否需要創建或運行。
下面這個例子使用了變量表達式:
deploy:
script: cap staging deploy
only:
refs:
- branches
variables:
- $RELEASE == "staging"
- $STAGING
下面這個例子,會根據提交日志信息來排除某些作業:
end-to-end:
script: rake test:end-to-end
except:
variables:
- $CI_COMMIT_MESSAGE =~ /skip-end-to-end-tests/
only:changes/except:changes
changes
策略表明一個作業只有在使用git push
事件使文件發生變化時執行。
下面這個例子中,deploy作業僅當流水線是計划作業或者在master主干運行:
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
only:
changes:
- Dockerfile
- docker/scripts/*
- dockerfiles/**/*
- more_scripts/*.{rb,py,sh}
上面這個例子中,一旦 Dockerfile
文件發生變化,或者 docker/scripts/
目錄下的文件發生變化,或者 dockerfiles/
目錄下的文件或目錄發生變化,或者 more_scripts/
目錄下 rb,py,sh
等腳本文件發生變化時,就會觸發Docker構建。
- 也可以使用
glob模式匹配
來匹配根目錄下的文件,或者任何目錄下的文件。
如下示例:
test: script: npm run test only: changes: - "*.json" - "**/*.sql"
Attention
在上面的示例中,glob模式匹配
的字符串需要使用雙引號包裹起來,否則會導致 .gitlab-ci.yml
解析錯誤。
下面這個例子,當md文件發生變化時,會忽略CI作業:
build: script: npm run build except: changes: - "*.md"
Warning
記錄一下官網說明中使用 change
時需要注意的兩點:
- Using changes with new branches and tags:When pushing a new branch or a new tag to GitLab, the policy always evaluates to true and GitLab will create a job. This feature is not connected with merge requests yet and, because GitLab is creating pipelines before a user can create a merge request, it is unknown what the target branch is at this point.
- Using changes with merge_requests:With pipelines for merge requests, it is possible to define a job to be created based on files modified in a merge request.
在合並請求中使用 change
策略:
docker build service one:
script: docker build -t my-service-one-image:$CI_COMMIT_REF_SLUG .
only:
refs:
- merge_requests
changes:
- Dockerfile
- service-one/**/*
上面這個例子中,一旦合並請求中修改了 Dockerfile
文件或者修改了 service
目錄下的文件,都會觸發Docker構建。
only
和 except
綜合示例
我們將 bluelog
項目的描述和主題進行修改:

並創建三個分支 issue-pylint
、Issue-flake8
和 severe-issues
:

剛新增的三個分支,自動繼承了master主干的CI RUNNER,因為Flake8檢查代碼質量沒通過,流水線都失敗了:

為了便於測試,將”meizhaohui”賬號設置為 bluelog
項目的主程序員!
現在朝 .gitlab-ci.yml
文件中增加 only
和 except
策略。
匹配 issue-
開頭的分支
創建僅匹配 issue-
開頭的分支:

可以發現master主干沒有執行 find Bugs
作業:

為了快速測試,我們對對個作業都使用 only
和 except
策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version # cloc . only: - /^issue-.*$/ except: - master script: - echo "Do your build here" - cloc --version # - cloc . tags: - bluelog find Bugs: stage: code_check only: - /^issue-.*$/ except: - branches script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version # - flake8 . tags: - bluelog test1: stage: test only: - /^issue-.*$/ except: - /issue-pylint/ script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test only: - /^issue-.*$/ except: - /Issue-flake8/ script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy only: - /^issue-.*$/ except: - /severe-issues/ script: - echo "Do your deploy here" tags: - bluelog
|
提交后,直接入庫,檢查master主干,並沒有觸發流水線作業。
統計作業流水線作業情況:
分支 | 流水線 | build1 | find Bugs | test1 | test2 | deploy1 |
master | 未觸發 | |||||
issue-pylint | #22 | Yes | No | No | Yes | Yes |
Issue-flake8 | 未觸發 | |||||
severe-issues | 未觸發 |

解釋上面的流水作業策略:
作業 | 規則定義 | 規則解釋 |
build1 | only: - /^issue-.*$/ except: - master |
只在以issue-開頭的分支執行,不在master主干執行 |
find Bugs | only: - /^issue-.*$/ except: - branches |
只在以issue-開頭的分支執行,不在 branches 分支執行, 由於issue-pylint也是分支,所以在issue-pylint中也不會執行find Bugs作業 |
test1 | only: - /^issue-.*$/ except: - /issue-pylint/ |
只在以issue-開頭的分支執行,不在issue-pylint分支執行, 即會在除了issue-pylint分支以外的issue-開頭的分支執行,也即沒有分支執行 |
test2 | only: - /^issue-.*$/ except: - /Issue-flake8/ |
只在以issue-開頭的分支執行,不在Issue-flake8分支執行, 因此可以issue-pylint分支執行 |
deploy1 | only: - /^issue-.*$/ except: - /severe-issues/ |
只在以issue-開頭的分支執行,不在severe-issues分支執行 因此可以issue-pylint分支執行 |
大小寫不敏感匹配
好,我們再將 only
語法中加入語法大小寫不敏感的 i
標志!再來做一次實驗,看看最終的效果。
加入語法大小寫不敏感的 i
標志:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version # cloc . only: - /^issue-.*$/i except: - master script: - echo "Do your build here" - cloc --version # - cloc . tags: - bluelog find Bugs: stage: code_check only: - /^issue-.*$/i except: - branches script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version # - flake8 . tags: - bluelog test1: stage: test only: - /^issue-.*$/i except: - /issue-pylint/ script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test only: - /^issue-.*$/i except: - /Issue-flake8/ script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy only: - /^issue-.*$/i except: - /severe-issues/ script: - echo "Do your deploy here" tags: - bluelog
|
預期效果: issue-pylint
和 Issue-flake8
分支會觸發流水線執行,master
主干和 severe-issues
分支不會觸發流水線執行。
統計作業流水線作業情況:
分支 | 流水線 | build1 | find Bugs | test1 | test2 | deploy1 |
master | 未觸發 | |||||
issue-pylint | #23 | Yes | No | No | Yes | Yes |
Issue-flake8 | #24 | Yes | No | Yes | No | Yes |
severe-issues | 未觸發 |
正如我們預期的一樣,issue-pylint
和 Issue-flake8
分支會觸發流水線執行,master
主干和 severe-issues
分支不會觸發流水線執行:


解釋上面的流水作業策略:
作業 | 規則定義 | 規則解釋 |
build1 | only: - /^issue-.*$/i except: - master |
只在以issue(不區分大小寫)-開頭的分支執行,不在master主干執行 可以在issue-pylint和Issue-flake8分支執行 |
find Bugs | only: - /^issue-.*$/i except: - branches |
只在以issue(不區分大小寫)-開頭的分支執行,不在 branches 分支執行, 由於issue-pylint也是分支,所以在issue-pylint中也不會執行find Bugs作業 |
test1 | only: - /^issue-.*$/i except: - /issue-pylint/ |
只在以issue(不區分大小寫)-開頭的分支執行,不在issue-pylint分支執行, 即會在除了issue-pylint分支以外的issue-(不區分大小寫)開頭的分支執行, 可以在Issue-flake8分支執行 |
test2 | only: - /^issue-.*$/i except: - /Issue-flake8/ |
只在以issue(不區分大小寫)-開頭的分支執行,不在Issue-flake8分支執行, 因此可以issue-pylint分支執行 |
deploy1 | only: - /^issue-.*$/i except: - /severe-issues/ |
只在以issue(不區分大小寫)-開頭的分支執行,不在severe-issues分支執行 可以在issue-pylint和Issue-flake8分支執行 |
我們再將 only
語法中將 /^issue-.*$/
改為 /issue/i
!再來做一次實驗,看看最終的效果。
不區分大小寫匹配issue字符:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version # cloc . only: - /issue/i except: - master script: - echo "Do your build here" - cloc --version # - cloc . tags: - bluelog find Bugs: stage: code_check only: - /issue/i except: - branches script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version # - flake8 . tags: - bluelog test1: stage: test only: - /issue/i except: - /issue-pylint/ script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test only: - /issue/i except: - /Issue-flake8/ script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy only: - /issue/i except: - /severe-issues/ script: - echo "Do your deploy here" tags: - bluelog
|
預期效果:不區分大小寫,issue-pylint
、 Issue-flake8
和 severe-issues
分支分支會觸發流水線執行,master
主干不會觸發流水線執行。
統計作業流水線作業情況:
分支 | 流水線 | build1 | find Bugs | test1 | test2 | deploy1 |
master | 未觸發 | |||||
issue-pylint | #25 | Yes | No | No | Yes | Yes |
Issue-flake8 | #26 | Yes | No | Yes | No | Yes |
severe-issues | #27 | Yes | No | Yes | Yes | No |
正如我們預期的一樣,issue-pylint
、 Issue-flake8
和 severe-issues
分支會觸發流水線執行,master
主干不會觸發流水線執行:



解釋上面的流水作業策略:
作業 | 規則定義 | 規則解釋 |
build1 | only: - /issue/i except: - master |
只在包含issue(不區分大小寫)字符的分支執行,不在master主干執行 因此在issue-pylint、Issue-flake8、severe-issues分支執行 |
find Bugs | only: - /issue/i except: - branches |
只在包含issue(不區分大小寫)字符的分支執行,不在 branches 分支執行, 所以find Bugs作業一直不會執行 |
test1 | only: - /issue/i except: - /issue-pylint/ |
只在包含issue(不區分大小寫)字符的分支執行,不在包含issue-pylint字符的分支 執行,即會在除了issue-pylint分支以外包含issue(不區分大小寫)字符的分支執行, 所以可以在Issue-flake8和severe-issues分支執行 |
test2 | only: - /issue/i except: - /Issue-flake8/ |
只在包含issue(不區分大小寫)字符的分支執行,不在包含issue-flake8字符的分支 執行,即會在除了issue-flake8分支以外包含issue(不區分大小寫)字符的分支執行, 所以可以在issue-pylint和severe-issues分支執行 |
deploy1 | only: - /issue/i except: - /severe-issues/ |
只在包含issue(不區分大小寫)字符的分支執行,不在包含severe-issues字符的分支 執行,即會在除了severe-issues分支以外包含issue(不區分大小寫)字符的分支執行, 所以可以在issue-pylint和Issue-flake8分支執行 |
git tag打標簽的使用
使用標簽,可以標記提交歷史上的特定點為重要提交。
- 新建tag
git tag -a v1.0 -m"Release v1.0"
上面的命令我們成功創建了本地一個版本 V1.0 ,並且添加了附注信息 ‘Release 1.0’。
- 查看tag
git tag
- 顯示tag附注信息
git show v1.0
- 提交本地tag到遠程倉庫
git push origin v1.0
- 提交本地所有tag到遠程倉庫
git push origin --tags
- 刪除本地tag
git tag -d v1.0
- 刪除遠程tag
git tag push origin :refs/tags/v1.0`
- 獲取遠程版本
git fetch origin tag v1.0
僅當tag標簽提交時,才觸發流水線執行
使用標簽,可以標記提交歷史上的特定點為重要提交,可以標記重要版本,如下圖,是GitLab官方的Tag標簽列表:

我們將流水線配置文件 .gitlab-ci.yml
修改為以下內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version # cloc . only: - tags except: - master script: - echo "Do your build here" - cloc --version # - cloc . tags: - bluelog find Bugs: stage: code_check only: - tags except: - branches script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version # - flake8 . tags: - bluelog test1: stage: test only: - tags except: - /issue-pylint/ script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test only: - tags except: - /Issue-flake8/ script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy only: - tags except: - /severe-issues/ script: - echo "Do your deploy here" tags: - bluelog
|
查看差異:
$ git diff
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7f16137..8315eb0 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,7 +28,7 @@ build1:
- cloc --version
# cloc .
only:
- - /^issue-.*$/
+ - tags
except:
- master
script:
@@ -41,7 +41,7 @@ build1:
find Bugs:
stage: code_check
only:
- - /^issue-.*$/
+ - tags
except:
- branches
script:
@@ -55,7 +55,7 @@ find Bugs:
test1:
stage: test
only:
- - /^issue-.*$/
+ - tags
except:
- /issue-pylint/
script:
@@ -67,7 +67,7 @@ test1:
test2:
stage: test
only:
- - /^issue-.*$/
+ - tags
except:
- /Issue-flake8/
script:
@@ -79,7 +79,7 @@ test2:
deploy1:
stage: deploy
only:
- - /^issue-.*$/
+ - tags
except:
- /severe-issues/
script:
提交:
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git add -A
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git commit -m"測試tag標簽觸發流水線執行"
[master eb9b468] 測試tag標簽觸發流水線執行
1 file changed, 7 insertions(+), 5 deletions(-)
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git push origin master:master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 365 bytes | 365.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To 192.168.56.14:higit/bluelog.git
1bd46f2..eb9b468 master -> master
查看是否觸發流水線,可以發現沒有觸發流水線執行:

我們給 bluelog
打個 tag
標簽,標簽名稱V0.1:
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git tag v0.1 -m"Release v0.1"
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git tag
v0.1
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git push origin v0.1
Enumerating objects: 1, done.
Counting objects: 100% (1/1), done.
Writing objects: 100% (1/1), 165 bytes | 165.00 KiB/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To 192.168.56.14:higit/bluelog.git
* [new tag] v0.1 -> v0.1
可以發現 bluelog
已經生成了一個tag版本:

在流水線列表中,也可以看#31號流水線被觸發了,並且標簽是v0.1:

使用流水線觸發器觸發流水線執行
我們給 bluelog
項目創建一個流水線觸發器( Trigger
),在項目的 設置
–> CI/CD
–> 流水線觸發器
處增加流水線觸發器:

在”觸發器描述”處填寫”bluelog trigger”,然后點擊”增加觸發器”按鈕,則會新增一個觸發器:

我們修改 .gitlab-ci.yml
配置文件,將 build1
和 find Bugs
作業設置為僅 triggers
觸發器能夠觸發執行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options before_script: - echo "Before script section" - echo "For example you might run an update here or install a build dependency" - echo "Or perhaps you might print out some debugging details" after_script: - echo "After script section" - echo "For example you might do some cleanup here" stages: - build - code_check - test - deploy build1: stage: build before_script: - echo "Before script in build stage that overwrited the globally defined before_script" - echo "Install cloc:A tool to count lines of code in various languages from a given directory." - yum install cloc -y after_script: - echo "After script in build stage that overwrited the globally defined after_script" - cloc --version # cloc . only: - triggers script: - echo "Do your build here" - cloc --version # - cloc . tags: - bluelog find Bugs: stage: code_check only: - triggers script: - echo "Use Flake8 to check python code" - pip install flake8 - flake8 --version # - flake8 . tags: - bluelog test1: stage: test only: - tags except: - /issue-pylint/ script: - echo "Do a test here" - echo "For example run a test suite" tags: - bluelog test2: stage: test only: - tags except: - /Issue-flake8/ script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy only: - tags except: - /severe-issues/ script: - echo "Do your deploy here" tags: - bluelog
|
提交修改:
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git diff
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 657dc5e..921f93e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,9 +28,7 @@ build1:
- cloc --version
# cloc .
only:
- - tags
- except:
- - master
+ - triggers
script:
- echo "Do your build here"
- cloc --version
@@ -41,9 +39,7 @@ build1:
find Bugs:
stage: code_check
only:
- - tags
- except:
- - branches
+ - triggers
script:
- echo "Use Flake8 to check python code"
- pip install flake8
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git add -A
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git commit -m"使用觸發器trigger觸發流水線執行"
[master 57f64a3] 使用觸發器trigger觸發流水線執行
1 file changed, 2 insertions(+), 6 deletions(-)
D:\data\github_tmp\higit\bluelog (master -> origin)
$ git push origin master:master
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 12 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 361 bytes | 361.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0)
To 192.168.56.14:higit/bluelog.git
eb9b468..57f64a3 master -> master
檢查發現並沒有觸發流水線的執行:

我們現在使用 curl
發送請求,觸發流水線觸發器執行:
[root@server ~]# curl -X POST -F token=cf8a32f6f8a583263f6d042e6362d2 -F ref=master http://192.168.56.14/api/v4/projects/2/trigger/pipeline {"id":33,"sha":"57f64a35cad6d069dc62ddc93f0747296383826e","ref":"master","status":"pending","web_url":"http://192.168.56.14/higit/bluelog/pipelines/33","before_sha":"0000000000000000000000000000000000000000","tag":false,"yaml_errors":null,"user":{"id":2,"name":"梅朝輝","username":"meizhaohui","state":"active","avatar_url":"http://192.168.56.14/uploads/-/system/user/avatar/2/avatar.png","web_url":"http://192.168.56.14/meizhaohui"},"created_at":"2019-07-06T22:08:52.761+08:00","updated_at":"2019-07-06T22:08:53.026+08:00","started_at":null,"finished_at":null,"committed_at":null,"duration":null,"coverage":null,"detailed_status":{"icon":"status_pending","text":"等待中","label":"等待中","group":"pending","tooltip":"等待中","has_details":false,"details_path":"/higit/bluelog/pipelines/33","illustration":null,"favicon":"/assets/ci_favicons/favicon_status_pending-5bdf338420e5221ca24353b6bff1c9367189588750632e9a871b7af09ff6a2ae.png"}}

可以發現流水線已經被執行,#33號流水線執行了 build1
和 find Bugs
作業,其他作業並未執行,與我們預期的相同:

根據流水線觸發器( Trigger
)創建處的提示,我們也可以在依賴項目中配置觸發器,依賴項目流水線結束時觸發此項目重新構建。
only
和 except
其他關鍵字的使用可參才官網文檔 https://docs.gitlab.com/ce/ci/yaml/README.html#onlyexcept-basic ,此處暫時不表。
allow_failure
allow_failure
可以用於當你想設置一個作業失敗的之后並不影響后續的CI組件的時候。失敗的作業不會影響到commit提交狀態。- 如果允許失敗的作業失敗了,則相應的作業會顯示一個黃色的警告,但對流水線成功與否不產生影響。
下面的這個例子中,job1和job2將會並列進行,如果job1失敗了,它也不會影響進行中的下一個階段,因為這里有設置了 allow_failure: true
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
job1: stage: test script: - execute_script_that_will_fail allow_failure: true job2: stage: test script: - execute_script_that_will_succeed job3: stage: deploy script: - deploy_to_staging
|
但是如果上面的job2執行失敗,那么job3則會受到影響而不會執行。
when
when
關鍵字用於實現在作業失敗時或發生故障時運行的作業 (when is used to implement jobs that are run in case of failure or despite the failure.)。
when
可以設置以下值:
on_success
:只有前面的階段的所有作業都成功時才執行,這是默認值。on_failure
:當前面階段的作業至少有一個失敗時才執行。always
: 無論前面的作業是否成功,一直執行本作業。manual
:手動執行作業,作業不會自動執行,需要人工手動點擊啟動作業。delayed
: 延遲執行作業,配合start_in
關鍵字一起作用,start_in
設置的值必須小於或等於1小時,start_in
設置的值示例:10 seconds
、30 minutes
、1 hour
,前面的作業結束時計時器馬上開始計時。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
stages: - build - cleanup_build - test - deploy - cleanup build_job: stage: build script: - make build cleanup_build_job: stage: cleanup_build script: - cleanup build when failed when: on_failure test_job: stage: test script: - make test deploy_job: stage: deploy script: - make deploy when: manual cleanup_job: stage: cleanup script: - cleanup after jobs when: always
|
說明:
- 只有在
build_job
構建作業失敗時,才會執行cleanup_build_job
作業。 - 需要在GitLab Web界面手動點擊,才能執行
deploy_job
部署作業。 - 無論之前的作業是否成功還是失敗,
cleanup_job
清理作業一直會執行。
延時處理的示例:
1 2 3 4 5 |
timed rollout 10%: stage: deploy script: echo 'Rolling out 10% ...' when: delayed start_in: 30 minutes
|
上面的例子創建了一個”timed rollout 10%”作業,會在上一個作業完成后30分鍾后才開始執行。
如果你點擊”Unschedule”按鈕可以取消一個激活的計時器,你也可以點擊”Play”按鈕,立即執行延時作業。
environment
environment
用於定義作業部署到特殊的環境中。如果指定了 environment
,並且在 運維
–> 環境
界面的環境列表中沒有該名稱下的環境,則會自動創建新環境。
在最簡單的格式中,環境關鍵字可以定義為:
1 2 3 4 5 |
deploy to production: stage: deploy script: git push production HEAD:master environment: name: production
|
上面的示例中,”deploy to production”作業將會部署代碼到”production”生產環境中去。
environment:name
- 在GitLab 8.11之前,環境的名稱可以使用
environment: production
方式定義,現在推薦使用name
關鍵字來定義環境的名稱,就像上面的示例一樣。 name
關鍵字的參數可以使用任何定義的CI變量,包括預定義的變量、安全變量、以及.gitlab-ci.yml
配置文件中定義的變量,但不能使用script
中定義的變量(因為這里面的變量是局部變量)。environment
環境的名稱可以包含:英文字母(letters)、數字(digits)、空格(space)、_、/、$、{、}等。常用的名稱有:qa
、staging
、production
。
Attention
- 軟件應用開發的經典模型有這樣幾個環境:開發環境(development)、集成環境(integration)、測試環境(testing)、QA驗證,模擬環境(staging)、生產環境(production)。
- 通常一個web項目都需要一個staging環境,一來給客戶做演示,二來可以作為production server的一個”預演”,正式發布新功能前能及早發現問題(特別是gem的依賴問題,環境問題等)。
- staging server可以理解為production環境的鏡像,QA在staging server上對新版本做最后一輪verification, 通過后才能deploy到產品線上。staging環境 盡最大可能來模擬產品線上的環境(硬件,網絡拓撲結構,數據庫數據)。
environment:url
environment:url
是可選的,用於設置環境的URL地址的按鈕,通過點擊按鈕可以訪問環境相應的URL地址。- 下面這個例子中,如果作業都成功完成,那么會在
評審請求
和環境部署
頁面創建一個Button按鈕,你點擊打開運行中的環境
按鈕就可以訪問環境對應的URL地址https://prod.example.com
。
示例:
1 2 3 4 5 6 |
deploy to production: stage: deploy script: git push production HEAD:master environment: name: production url: https://prod.example.com
|
environment:on_stop
與 environment:action
environment:on_stop
與environment:action
配合使用。- 可以通過
environment:on_stop
關鍵字定義一個關閉(停止)環境的作業。 action
關鍵字在關閉環境的作業中定義。
下面的例子聯合使用 environment:on_stop
與 environment:action
來關閉環境:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
review_app: stage: deploy script: make deploy-app environment: name: review on_stop: stop_review_app stop_review_app: stage: deploy script: make delete-app when: manual environment: name: review action: stop
|
在上面的示例中,設置 review_app
作業用於部署代碼到 review
評審環境中,同時在 on_stop
中指定了 stop_review_app
作業。一旦 review_app
作業成功執行,就會觸發 when
關鍵字定義的 stop_review_app
作業。通過設置為 manual
手動,需要在GitLab WEB界面點擊來允許 manual action
。
stop_review_app
作業必須配合定義以下關鍵字:
when
: 何時執行刪除或停止環境作業environment:name
: 環境名稱需要與上面的review_app
作業保持一致,即review
評審環境environment:action
:執行何種執行,stop
停止環境stage
:與review_app
作業的階段保持一致,都是deploy
運行完成后,在 stop_review_app
作業界面需要手動點擊 停止當前環境
才能啟動 stop_review_app
作業的執行。 stop_review_app
作業執行完成后,會停止 review
評審環境,在 環境
–> 已停止
列表中可以看到 review
評審環境。
Dynamic environments 動態環境
正如前面講解的,可以在環境的名稱中使用變量,在 environment:name
和 environment:url
中使用變量,則可以達到動態環境的目的,動態環境需要底層應用的支持。
我們不詳細展開,下面是官方的一個示例的改版:
1 2 3 4 5 6 |
deploy as review app: stage: deploy script: make deploy environment: name: review/${CI_COMMIT_REF_NAME} url: https://${CI_ENVIRONMENT_SLUG}.example.com/
|
上面示例中的 ${CI_COMMIT_REF_NAME}
${CI_ENVIRONMENT_SLUG}
就是兩個變量。
cache
GitLab Runner v0.7.0
引入cache
緩存機制。cache
緩存機制,可以在全局設置或者每個作業中設置。- 從
GitLab 9.0
開始,cache
緩存機制,可以在不同的的流水線或作業之間共享數據。 - 從
GitLab 9.2
開始, 在artifacts
工件之前恢復緩存。 cache
緩存機制用於指定一系列的文件或文件夾在不同的流水線或作業之間共享數據,僅能使用項目工作空間(project workspace
)中的路徑作為緩存的路徑。如果 ``cache
配置的路徑是作業工作空間外部,則說明配置是全局的緩存,所有作業共享。- 訪問 Cache dependencies in GitLab CI/CD 文檔來獲取緩存是如何工作的以及好的實踐實例的例子。
cache
緩存機制的其他介紹請參考 https://docs.gitlab.com/ce/ci/yaml/README.html#cache 。
artifacts
artifacts
用於指定在作業成功、失敗、或者一直等狀態下時,一系列的文件或文件夾附加到作業中。artifacts
可以稱為工件``或者 ``歸檔文件
。- 作業完成后,工件被發送到GitLab,可以在GitLab Web界面下載。
- 默認情況下,只有成功的作業才會生成工件。
- 並不是所有的
executor
執行器都支持工件。 - 工件的詳細介紹可參考 Introduction to job artifacts
artifacts:paths
artifacts:paths
用於指定哪些文件或文件夾會被打包成工件,僅僅項目工作空間(project workspace
)的路徑可以使用。- 要在不同作業間傳遞工作,請參數 dependencies
下面示例,將目錄 binaries/
和文件 .config
打包成工件:
1 2 3 4 |
artifacts: paths: - binaries/ - .config
|
要禁用工件傳遞,請使用空依賴關系定義作業:
1 2 3 4 |
job: stage: build script: make build dependencies: []
|
你可以僅為打標記的release發布版本創建工作,這樣可以避免臨時構建產生大量的存儲需求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
default-job: script: - mvn test -U except: - tags release-job: script: - mvn package -U artifacts: paths: - target/*.war only: - tags
|
上面的示例中,default-job
作業不會在打標記的release發布版本中執行,而 release-job
只會在打標記的release發布版本執行,並且將 target/*.war
打包成工件以供下載。
artifacts:name
- 工件的默認名稱是
artifacts
,當下載時名稱是artifacts.zip
。 - 通過
artifacts:name
關鍵字可以自定義工件的歸檔名稱,這樣你可以為每個工件設置獨一無二的名稱,歸檔名稱可以使用預定義的變量。 - 如果分支名稱中包含斜杠(比如
feature/my-feature
),推薦使用$CI_COMMIT_REF_SLUG
代替$CI_COMMIT_REF_NAME
作為工件名稱。
使用作業名稱使用工件名稱:
1 2 3 4 5 |
job: artifacts: name: "$CI_JOB_NAME" paths: - binaries/
|
使用當前分支或tag版本標簽名作為工件名稱:
1 2 3 4 5 |
job: artifacts: name: "$CI_COMMIT_REF_NAME" paths: - binaries/
|
同時使用當前作業名稱以及當前分支或tag版本標簽名作為工件名稱:
1 2 3 4 5 |
job: artifacts: name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME" paths: - binaries/
|
同時使用當前作業階段名稱以及當前分支名稱作為工件名稱:
1 2 3 4 5 |
job: artifacts: name: "$CI_JOB_STAGE-$CI_COMMIT_REF_NAME" paths: - binaries/
|
如果你使用的 Windows系統的Batch批處理腳本 ,則需要把 $
替換成 %
:
1 2 3 4 5 |
job: artifacts: name: "%CI_JOB_STAGE%-%CI_COMMIT_REF_NAME%" paths: - binaries/
|
如果你使用的 Windows系統的PowerShell腳本 ,則需要把 $
替換成 $env:
:
1 2 3 4 5 |
job: artifacts: name: "$env:CI_JOB_STAGE-$env:CI_COMMIT_REF_NAME" paths: - binaries/
|
artifacts:untracked
artifacts:untracked
用於將git未加入版本庫的文件作為工件文件。artifacts:untracked
將會忽略配置文件.gitignore
。
將所有的未跟蹤文件打包成工件:
1 2 |
artifacts: untracked: true
|
將所有的未跟蹤文件以及目錄 binaries
中文件打包成工件:
1 2 3 4 |
artifacts: untracked: true paths: - binaries/
|
artifacts:when
artifacts:when
用於在作業失敗時或者忽略失敗時上傳工件。
artifacts:when
可以設置以下值:
on_success
,默認值,當作業成功上傳工件。on_failure
,當作業失敗上傳工件。always
,無論作業是否成功一直上傳工件。
當作業失敗時,上傳工件:
1 2 3 |
job: artifacts: when: on_failure
|
artifacts:expire_in
-
artifacts:expire_in
用於設置工件的過期時間。 -
你可以點擊界面上的
Keep
保持按鈕,永久保存工件。 -
工件到期后,默認情況下每小時刪除一次工件(通過cron作業),並且后續不能再訪問該工件。
-
工件默認有效期是30天,可以通過
Admin area
–>Settings
–>Continuous Integration and Deployment
設置默認的有效性時間。 -
如果你不提供時間單位的話,工作有效性的時間是以秒為單位的時間,下面是一些示例:
- ‘42’
- ‘3 mins 4 sec’
- ‘2 hrs 20 min’
- ‘2h20min’
- ‘6 mos 1 day’
- ‘47 yrs 6 mos and 4d’
- ‘3 weeks and 2 days’
下面示例中工件有效期為一周:
1 2 3 |
job: artifacts: expire_in: 1 week
|
artifacts:reports
artifacts:reports
用於收集測試報告(report),並在GitLab UI界面中顯示出來。- 無論作業是否成功,都會收集測試報告。
- 可以通過設置工件的打包路徑
artifacts:paths
添加測試的報告輸出文件。 artifacts:reports:junit
可以用來收集單元測試的報告,查看 JUnit test reports 獲取更詳細的信息和示例。
下面是從Ruby的RSpec測試工具中收集JUnit XML文件的示例:
1 2 3 4 5 6 7 8 |
rspec: stage: test script: - bundle install - rspec --format RspecJunitFormatter --out rspec.xml artifacts: reports: junit: rspec.xml
|
Note
如果你的測試報告是多個XML文件,你可以在一個作業中指定多個單元測試報告,GitLab會自動將他們轉換成一個文件,可以像下面這樣表示報告的路徑:
- 文件匹配模式:
junit: rspec-*.xml
- 文件列表:
junit: [rspec-1.xml, rspec-2.xml, rspec-3.xml]
- 混合模式:
junit: [rspec.xml, test-results/TEST-*.xml]
下面是Go語言收集JUnit XML文件的示例:
1 2 3 4 5 6 7 8 9 |
## Use https://github.com/jstemmer/go-junit-report to generate a JUnit report with go
golang: stage: test script: - go get -u github.com/jstemmer/go-junit-report - go test -v 2>&1 | go-junit-report > report.xml artifacts: reports: junit: report.xml
|
下面是C/C++語言使用GoogleTest進行單元測試,收集JUnit XML文件的示例:
1 2 3 4 5 6 7 |
cpp: stage: test script: - gtest.exe --gtest_output="xml:report.xml" artifacts: reports: junit: report.xml
|
Attention
如果GoogleTest需要運行在多個平台(如 x86
、 x64
、arm
),需要為每種平台設置唯一的報告名稱,最后將結果匯總起來。
還有一些其他的報告關鍵字,但社區版不可用,忽略不提。
dependencies
dependencies
依賴關鍵字應該與artifacts
工件關鍵字聯合使用,允許你在不同作業間傳遞工件。- 默認情況下,會傳遞所有本作業之前階段的所有工件。
- 需要在作業上下文中定義
dependencies
依賴關鍵字,並指出所有需要使用的前序工件的作業名稱列表。 作業列表中不能使用該作業后的作業名稱 。 - 定義空的依賴項,將下不會下載任何工件。
- 使用依賴項不會考慮前面作業的運行狀態。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
build:osx: stage: build script: make build:osx artifacts: paths: - binaries/ build:linux: stage: build script: make build:linux artifacts: paths: - binaries/ test:osx: stage: test script: make test:osx dependencies: - build:osx test:linux: stage: test script: make test:linux dependencies: - build:linux deploy: stage: deploy script: make deploy
|
上面示例中, build:osx
和 build:linux
兩個作業定義了工件, test:osx
作業執行時,將會下載並解壓 build:osx
的工件內容。相應的, test:linux
也會獲取 build:linux
的工件。 deploy
作業會下載全部工件。
Attention
如果作為依賴的作業的工件過期或者被刪除,那么依賴這個作業的作業將會失敗。
coverage
coverage
可以從作業的輸出log中提取代碼覆蓋率。- 僅支持正則表達式方式獲取覆蓋率。
- 字符串的前后必須使用/包含來表明一個正確的正則表達式規則。特殊字符串需要轉義。
下面是一個簡單的例子:
1 2 |
job1: coverage: '/Code coverage:\d+\.\d+%/'
|
如在作業日志中輸出了”Code coverage:80.2%”,我們使用上面的正則表達式就可以獲取到代碼的覆蓋率。然后在作業的右上角處就會顯示 Coverage:80.2%
。
retry
retry
重試關鍵字用於配置當作業失敗時可以重新執行的次數。- 當作業失敗時,如果配置了
retry
,那么該作業就會重試,直到允許的最大次數。 - 如果
retry
設置值為2,如果第一次重試運行成功了,那么就不會進行第二次重試。 retry
設置值只能是0、1、2三個整數。
下面是一個簡單的例子:
1 2 3 |
test: script: rspec retry: 2
|
-
為了更好的控制重試次數,
retry
可以設置以下兩個關鍵字:max
: 最大重試次數when
: 何時重試
下面這個例子只有當運行器系統出現故障時才能最多重試兩次:
1 2 3 4 5 |
test: script: rspec retry: max: 2 when: runner_system_failure
|
如果上面例子中出現的是其他故障,那么作業不會重試。
為了針對多種重試情形,我們可以使用矩陣形式羅列出錯誤情形,如下示例:
1 2 3 4 5 6 7 |
test: script: rspec retry: max: 2 when: - runner_system_failure - stuck_or_timeout_failure
|
when
可以是以下值:
always
: 一直重試,默認值。unknown_failure
:當錯誤未知時重試。script_failure
: 腳本錯誤時重試。api_failure
: API調用錯誤時重試。stuck_or_timeout_failure
: 作業卡信或超時錯誤時重試。runner_system_failure
: 運行器系統錯誤(如設置工作失敗)時重試。missing_dependency_failure
: 依賴工件丟失錯誤時重試。runner_unsupported
: 運行器不支持錯誤時重試。
pages
pages
是一項特殊工作,用於將靜態內容上傳到GitLab,可用於為您的網站提供服務。詳情請查看官網指導 GitLab Pages
variables
- 在
.gitlab-ci.yml
配置文件中可以通過variables
關鍵字配置全局變量或者作業級的局部變量。 - 當
variables
關鍵字使用在作業層級時,它會覆蓋全局變量或預定義變量。 - 可以在
variables
關鍵字中定義非敏感性配置。 - 全局變量可以在各個作業中作業,而作業級別的局部變量只能在該作業中使用。
- 可以在GitLab WEB界面定義一些敏感性配置變量,或者可能變動的變量。
- 在
script
中使用export
可以導出當前可用的變量信息。 - 作業內部修改全局變量只對當前作用生效,不會影響其他作業。
- 可以使用賦值語句對全局變量或局部變量進行重新賦值。
下面這個示例定義一個全局數據庫的URL地址:
1 2 |
variables: DATABASE_URL: "postgres://postgres@postgres/my_database"
|
下面修改 bluelog
項目的配置文件為如下內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options # 定義全局變量 variables: # 數據庫信息 SQLALCHEMY_DATABASE_URI: 'mysql+pymysql://root:root@localhost:3306/bluelog?charset=utf8mb4' # 不發送警告通知 SQLALCHEMY_TRACK_MODIFICATIONS: "False" # 顯示執行SQL SQLALCHEMY_ECHO: "True" stages: - build - code_check - test - deploy build1: stage: build variables: # 數據庫信息 SQLALCHEMY_DATABASE_URI: 'mysql+pymysql://root:123456@localhost:3306/bluelog?charset=utf8mb4' # 不顯示執行SQL SQLALCHEMY_ECHO: "False" script: - export - echo "Do your build here" - cloc --version - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" tags: - bluelog find Bugs: stage: code_check script: - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" - SQLALCHEMY_ECHO="Nothing" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" tags: - bluelog test1: stage: test variables: # CKEditor富文本設置 CKEDITOR_SERVE_LOCAL: "True" script: - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" - echo -e "CKEDITOR_SERVE_LOCAL:${CKEDITOR_SERVE_LOCAL}" tags: - bluelog test2: stage: test script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy script: - echo "Do your deploy here" tags: - bluelog
|
查看各階段的輸出內容。

可以看到 build1
作業中:
SQLALCHEMY_DATABASE_URI
已經覆蓋了全局定義的SQLALCHEMY_DATABASE_URI
,看差異數據庫URL中全局是”root:root”,而作業中是”root:123456”。- 由於作業中並沒有定義
SQLALCHEMY_TRACK_MODIFICATIONS
變量,所以使用的是全局的SQLALCHEMY_TRACK_MODIFICATIONS
變量,輸出結果是”False”。 - 作業中定義的
SQLALCHEMY_ECHO: "False"
將全局的SQLALCHEMY_ECHO: "True"
覆蓋,最后顯示的是”False”。
再看 find Bugs
作業:

- 因為沒有定義
variables
關鍵字,這個作用將使用全局變量。 - 39、40、41三行輸出的結果都是全局變量定義的值。
- 42行的
SQLALCHEMY_ECHO="Nothing"
對SQLALCHEMY_ECHO
全局變量進行的重新賦值,43行打印出了賦值后的新值是”Nothing”。 - 上面兩個作業說明,作業內部修改全局變量只對當前作用生效,不會影響其他作業。
- 可以使用賦值語句對全局變量或局部變量進行重新賦值。
再看 test1
作業:

- 該作業定義
variables
關鍵字,增加了一個CKEDITOR_SERVE_LOCAL
變量。 - 上一個作業的修改
SQLALCHEMY_ECHO="Nothing"
對本作業顯示SQLALCHEMY_ECHO
變量沒有影響,仍然會顯示全局變量定義的值”True”。再一次證明了作業內部修改全局變量只對當前作用生效,不會影響其他作業。
variables
變量的優先級
variables
變量的優先級參考 Priority of environment variables
原文:
Variables of different types can take precedence over other variables, depending on where they are defined. The order of precedence for variables is (from highest to lowest): Trigger variables or scheduled pipeline variables. Project-level variables or protected variables. Group-level variables or protected variables. YAML-defined job-level variables. YAML-defined global variables. Deployment variables. Predefined environment variables.
翻譯過來,是這樣的:
不同類型的變量可以優先於其他變量,具體取決於它們的定義位置。
變量的優先順序是(從最高到最低):
觸發變量或預定的流水線變量。
項目級別變量或受保護變量。
組級別變量或受保護變量。
YAML定義的作業級變量。
YAML定義的全局變量。
部署環境變量。
預定義的環境變量。
變量中有一些關於git策略的特殊變量,如后續幾個小節,當前僅列出,后續詳細補充。
使用export導出的變量示例
export的導出示例:
$ export
declare -x CI="true"
declare -x CI_API_V4_URL="http://192.168.56.14/api/v4"
declare -x CI_BUILDS_DIR="/root/gitlab-runner/builds"
declare -x CI_BUILD_BEFORE_SHA="84f1f0e417d7e340770a4bb05076bf74f3231991"
declare -x CI_BUILD_ID="128"
declare -x CI_BUILD_NAME="build1"
declare -x CI_BUILD_REF="a6554ffa0d2ae67c675fe9768f702f0b1bb65f5a"
declare -x CI_BUILD_REF_NAME="master"
declare -x CI_BUILD_REF_SLUG="master"
declare -x CI_BUILD_STAGE="build"
declare -x CI_BUILD_TOKEN="[MASKED]"
declare -x CI_COMMIT_BEFORE_SHA="84f1f0e417d7e340770a4bb05076bf74f3231991"
declare -x CI_COMMIT_DESCRIPTION=""
declare -x CI_COMMIT_MESSAGE="全局變量與局部變量的使用
"
declare -x CI_COMMIT_REF_NAME="master"
declare -x CI_COMMIT_REF_SLUG="master"
declare -x CI_COMMIT_SHA="a6554ffa0d2ae67c675fe9768f702f0b1bb65f5a"
declare -x CI_COMMIT_SHORT_SHA="a6554ffa"
declare -x CI_COMMIT_TITLE="全局變量與局部變量的使用"
declare -x CI_CONCURRENT_ID="0"
declare -x CI_CONCURRENT_PROJECT_ID="0"
declare -x CI_CONFIG_PATH=".gitlab-ci.yml"
declare -x CI_JOB_ID="128"
declare -x CI_JOB_NAME="build1"
declare -x CI_JOB_STAGE="build"
declare -x CI_JOB_TOKEN="[MASKED]"
declare -x CI_JOB_URL="http://192.168.56.14/higit/bluelog/-/jobs/128"
declare -x CI_NODE_TOTAL="1"
declare -x CI_PAGES_DOMAIN="example.com"
declare -x CI_PAGES_URL="http://higit.example.com/bluelog"
declare -x CI_PIPELINE_ID="45"
declare -x CI_PIPELINE_IID="48"
declare -x CI_PIPELINE_SOURCE="push"
declare -x CI_PIPELINE_URL="http://192.168.56.14/higit/bluelog/pipelines/45"
declare -x CI_PROJECT_DIR="/root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog"
declare -x CI_PROJECT_ID="2"
declare -x CI_PROJECT_NAME="bluelog"
declare -x CI_PROJECT_NAMESPACE="higit"
declare -x CI_PROJECT_PATH="higit/bluelog"
declare -x CI_PROJECT_PATH_SLUG="higit-bluelog"
declare -x CI_PROJECT_URL="http://192.168.56.14/higit/bluelog"
declare -x CI_PROJECT_VISIBILITY="private"
declare -x CI_REGISTRY_PASSWORD="[MASKED]"
declare -x CI_REGISTRY_USER="gitlab-ci-token"
declare -x CI_REPOSITORY_URL="http://gitlab-ci-token:[MASKED]@192.168.56.14/higit/bluelog.git"
declare -x CI_RUNNER_DESCRIPTION="bluelog runner"
declare -x CI_RUNNER_EXECUTABLE_ARCH="linux/amd64"
declare -x CI_RUNNER_ID="1"
declare -x CI_RUNNER_REVISION="3001a600"
declare -x CI_RUNNER_TAGS="bluelog"
declare -x CI_RUNNER_VERSION="11.10.0"
declare -x CI_SERVER="yes"
declare -x CI_SERVER_NAME="GitLab"
declare -x CI_SERVER_REVISION="8a802d1c6b7"
declare -x CI_SERVER_VERSION="11.10.6"
declare -x CI_SERVER_VERSION_MAJOR="11"
declare -x CI_SERVER_VERSION_MINOR="10"
declare -x CI_SERVER_VERSION_PATCH="6"
declare -x CI_SHARED_ENVIRONMENT="true"
declare -x CONFIG_FILE="/etc/gitlab-runner/config.toml"
declare -x FF_K8S_USE_ENTRYPOINT_OVER_COMMAND="true"
declare -x FF_USE_LEGACY_GIT_CLEAN_STRATEGY="false"
declare -x GITLAB_CI="true"
declare -x GITLAB_FEATURES=""
declare -x GITLAB_USER_EMAIL="mzh.whut@gmail.com"
declare -x GITLAB_USER_ID="2"
declare -x GITLAB_USER_LOGIN="meizhaohui"
declare -x GITLAB_USER_NAME="梅朝輝"
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="server.hopewait"
declare -x LANG="en_US.utf8"
declare -x LC_ALL="en_US.utf8"
declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="root"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:"
declare -x MAIL="/var/spool/mail/root"
declare -x OLDPWD="/root/gitlab-runner"
declare -x PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin"
declare -x PIPENV_PYPI_MIRROR="https://mirrors.aliyun.com/pypi/simple"
declare -x PIPENV_VENV_IN_PROJECT="1"
declare -x PWD="/root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog"
declare -x SHELL="/bin/bash"
declare -x SHLVL="3"
declare -x SQLALCHEMY_DATABASE_URI="mysql+pymysql://root:123456@localhost:3306/bluelog?charset=utf8mb4"
declare -x SQLALCHEMY_ECHO="False"
declare -x SQLALCHEMY_TRACK_MODIFICATIONS="False"
declare -x SSH_CLIENT="192.168.56.1 51472 22"
declare -x SSH_CONNECTION="192.168.56.1 51472 192.168.56.14 22"
declare -x SSH_TTY="/dev/pts/0"
declare -x TERM="linux"
declare -x USER="root"
declare -x XDG_RUNTIME_DIR="/run/user/0"
declare -x XDG_SESSION_ID="41"
Attention
- 不要將敏感信息,如用戶密碼、Token等信息放在
.gitlab-ci.yml
配置文件中定義變量。 - 敏感信息可以WEB配置界面添加變量,並將變量設置為
Protected受保護
或者Masked
,設置為Masked
的變量不會直接顯示在作業日志信息中。
變量定義時使用其他變量
- 可以在變量定義時,使用其他的變量,需要使用
$$
進行轉義。
看下面的示例:
1 2 3 4 5 |
variables: LS_CMD: 'ls $FLAGS $$TMP_DIR' FLAGS: '-al' script: - 'eval $LS_CMD' # will execute 'ls -al $TMP_DIR'
|
克隆策略Git strategy GIT_STRATEGY
- 你可以通過設置
GIT_STRATEGY
變量來指定GitLab Runner運行作業時使用什么樣的方式來獲取最新的代碼,可以在全局級或作業級進行設置。 GIT_STRATEGY
變量可以設置為fetch
、clone
、none
。clone
是最慢的方式,這種方式會從頭開始克隆倉庫。fetch
相對來說更快一點,如果本地項目空間中存在遠程倉庫的克隆,只用從遠程獲取最新到本地,而不用從頭開始克隆整個倉庫(如果本地項目空間不存在遠程倉庫的克隆的話,則此時等同於clone,從頭開始克隆遠程倉庫)。none
也是利用本地項目空間中的文件,但不會從遠程獲取到最新的修改數據,本地數據不是最新的。
下面我們通過修改 .gitlab-ci.yml
配置文件來查看這個現象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options stages: - build - code_check - test - deploy build1: stage: build script: - pwd - export - echo "Do your build here" - echo "GIT_STRATEGY:${GIT_STRATEGY}" tags: - bluelog find Bugs: stage: code_check variables: GIT_STRATEGY: "fetch" script: - pwd - echo "GIT_STRATEGY:${GIT_STRATEGY}" tags: - bluelog test1: stage: test variables: GIT_STRATEGY: "clone" script: - pwd - echo "GIT_STRATEGY:${GIT_STRATEGY}" tags: - bluelog test2: stage: test variables: GIT_STRATEGY: "none" script: - echo "GIT_STRATEGY:${GIT_STRATEGY}" tags: - bluelog deploy1: stage: deploy script: - echo "Do your deploy here" tags: - bluelog
|
提交后,流水線觸發了:

我們檢查一下每個作業的log日志信息:
先看build1作業:


可以看到默認情況下,會使用 git fetch
方式來獲取最新的修改,並且 echo "GIT_STRATEGY:${GIT_STRATEGY}"
打印 ${GIT_STRATEGY}
變量為空,也就是默認情況下GitLab並不會設置 GIT_STRATEGY
變量。
再看一下find Bugs作業:

此處也是直接使用現有項目空間里面的本地倉庫,使用 git fetch
方式來獲取最新的修改,由於在作業級中設置了 GIT_STRATEGY
變量,最后打印出打印 ${GIT_STRATEGY}
變量的值為 fetch
。
再看一下test1作業:

因為設置了 GIT_STRATEGY: "clone"
,這個時候GitLab Runner會從頭開始克隆遠程倉庫,最后打印出打印 ${GIT_STRATEGY}
變量的值為 clone
。
再看一下test2作業:

因為設置了 GIT_STRATEGY: "none"
,這個時候GitLab Runner什么也不做,不會獲取最新的修改,最后打印出打印 ${GIT_STRATEGY}
變量的值為 none
。
我們再修改一下配置文件為下面的內容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options stages: - build - code_check - test - deploy build1: stage: build script: - pwd - export - echo "Do your build here" - echo "GIT_STRATEGY:${GIT_STRATEGY}" - du -sh - ls -lah README.md tags: - bluelog find Bugs: stage: code_check variables: GIT_STRATEGY: "fetch" script: - pwd - echo "GIT_STRATEGY:${GIT_STRATEGY}" - du -sh - ls -lah README.md when: manual tags: - bluelog test1: stage: test variables: GIT_STRATEGY: "clone" script: - pwd - echo "GIT_STRATEGY:${GIT_STRATEGY}" - du -sh - ls -lah README.md when: manual tags: - bluelog test2: stage: test variables: GIT_STRATEGY: "none" script: - echo "GIT_STRATEGY:${GIT_STRATEGY}" - du -sh - ls -lah README.md when: manual tags: - bluelog deploy1: stage: deploy script: - echo "Do your deploy here" - du -sh - ls -lah README.md when: manual tags: - bluelog
|
提交后,流水線觸發了,但有build1作業后面的作業需要手動執行:

我們檢查build1作業:

可以獲取到整個倉庫的大小,也可以讀取到倉庫中”README.md”文件。
假設我們此時在服務器端將 /root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog
和 /root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog.tmp
目錄刪除,並觸發find Bugs作業運行:

因為設置了 GIT_STRATEGY: "fetch"
,但因為我把項目空間里面的本地倉庫內容都刪除了,這個時候GitLab Runner發現本地並沒有遠程倉庫的文件,只能從頭開始克隆遠程倉庫,最后打印出打印 ${GIT_STRATEGY}
變量的值為 fetch
。

再觸發test1作業運行,還是從頭開始下載遠程倉庫:

關鍵一步,我們再次刪除工作空間中的 /root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog
和 /root/gitlab-runner/builds/1aXYZ5H9/0/higit/bluelog.tmp
目錄:

再觸發test2作業運行:

此時發現,GitLab Runner僅僅創建了一個目錄 bluelog
,但不從遠程獲取數據,這個時候我們獲取倉庫目錄數據大小為0,也查看不到README.md文件的詳情,由於沒有README.md文件,執行命令就報錯。
- 可以看出設置
GIT_STRATEGY: "none"
可能會遇到意想不到的情況! - 為了加快流水線工程的執行,建議使用
fetch
模式。 - 流水線的Git策略默認是
git fetch
模式。
流水線的默認Git策略,可以在項目的流水線通用設置中查看:

子模塊策略Git submodule strategy GIT_SUBMODULE_STRATEGY
GIT_SUBMODULE_STRATEGY
類似於GIT_STRATEGY
,當你的項目需要包含別的項目代碼時,可以將別的項目作為你的項目的子模塊,這個時候就可以使用GIT_SUBMODULE_STRATEGY
。GIT_SUBMODULE_STRATEGY
默認取值none
,即拉取代碼時,子模塊不會被引入。GIT_SUBMODULE_STRATEGY
可取值normal
,意味着在只有頂級子模塊會被引入。GIT_SUBMODULE_STRATEGY
可取值recursive
,遞歸的意思,意味着所有級子模塊會被引入。
子模塊需要配置在 .gitmodules
配置文件中,下面是兩個示例:
場景:
- 你的項目地址:
https://gitlab.com/secret-group/my-project
,你可以使用git clone git@gitlab.com:secret-group/my-project.git
檢出代碼。 - 你的項目依賴
https://gitlab.com/group/project
,你可以將這個模塊作為項目的子模塊。
子模塊與本項目在同一個服務上,可以使用相對引用:
1 2 3 |
[submodule "project"] path = project url = ../../group/project.git
|
子模塊與本項目不在同一個服務上,使用相對絕對URL:
1 2 3 |
[submodule "project-x"] path = project-x url = https://gitserver.com/group/project-x.git
|
檢出分支設置Git checkout GIT_CHECKOUT
-
當
GIT_STRATEGY
設置為fetch
或者clone
時,可以通過GIT_CHECKOUT
變量設置是否需要做git checkout
操作,如果未指定該參數,默認值為true
,即需要做git checkout
操作。 -
可以在全局級或作業級進行設置。
-
如果
GIT_CHECKOUT
變量設置為true
,GitLab Runner都會將本地工作副本檢出並切換到當前流水線相關的修訂版本分支上。 -
如果
GIT_CHECKOUT
變量設置為false
,那么運行器操作如下:fetch
操作時,更新倉庫並在當前版本上保留工作副本。clone
操作時,克隆倉庫並在默認分支中保留工作副本。
下面示例不進行自動切換到分支:
1 2 3 4 5 6 |
variables: GIT_STRATEGY: clone GIT_CHECKOUT: "false" script: - git checkout -B master origin/master - git merge $CI_COMMIT_SHA
|
清理工作Git clean flags GIT_CLEAN_FLAGS
- 可以使用
GIT_CLEAN_FLAGS
變量來控制在檢出源碼后git clean
的默認行為,可以在全局級或作業級進行設置。 GIT_CLEAN_FLAGS
變量接受git clean
命令的所有參數。- 如果指定了
GIT_CHECKOUT: "false"
,那么git clean
將不可用。 git-clean
: Remove untracked files from the working tree,即刪除未跟蹤的文件。git clean
命令用來從你的工作目錄中刪除所有沒有tracked過的文件,git reset --hard
用於刪除跟蹤文件的修改記錄。git clean -n
命令列出將被刪除的文件。git clean -f
命令刪除當前目錄下所有沒有跟蹤過的文件。git clean -d
命令刪除當前目錄下所有沒有跟蹤過的目錄。git clean -e <pattern>
命令排除(--exclude=<pattern>
) 某文件或目錄,即不刪除模式匹配的文件。git clean -ffxd
命令刪除當前目錄(包括由其他git倉庫管理的子目錄)下所有沒有跟蹤過的目錄和文件。GIT_CLEAN_FLAGS
變量未指定時,git clean
命令的參數是-ffxd
。GIT_CLEAN_FLAGS
變量指定為none
時,git clean
命令不會執行。
下面示例用於刪除未被跟蹤文件和目錄,但排除cache目錄及目錄下的文件:
1 2 3 4 |
variables: GIT_CLEAN_FLAGS: -ffdx -e cache/ script: - ls -al cache/
|
作業重試次數 Job stages attempts
- 您可以設置正在運行的作業嘗試執行以下每個階段的嘗試次數。可以在全局級或作業級進行設置。
- 涉及三個變量
GET_SOURCES_ATTEMPTS
、ARTIFACT_DOWNLOAD_ATTEMPTS
、RESTORE_CACHE_ATTEMPTS
。 GET_SOURCES_ATTEMPTS
變量設置獲取源碼的嘗試次數。ARTIFACT_DOWNLOAD_ATTEMPTS
變量設置下載歸檔文件的嘗試次數。RESTORE_CACHE_ATTEMPTS
變量設置重建緩存的嘗試次數。- 默認是1次嘗試。
示例:
1 2 |
variables: GET_SOURCES_ATTEMPTS: 3
|
淺克隆 Shallow cloning GIT_DEPTH
- GitLab 8.9中引入了試驗性的特征
淺克隆
,在將來的版本中有可能改變或者完全移除。 - 可以通過設置
GIT_DEPTH
克隆深度,不詳細介紹,可參考 Shallow cloning
廢棄的關鍵字 types
和 type
- 關鍵字
types
和type
已經廢棄。 - 使用
stages
階段定義關鍵字代替types
。 - 使用
stage
作業所處階段關鍵字代替type
。
使用 GIT_CLONE_PATH
自定義構建目錄
- 在默認情況下,自定義構建目錄只有在GitLab Runner運行器配置文件中定義了
custom_build_dir
為enabled
開啟狀態時才可使用。 docker
、kubernetes
運行器默認開啟了此功能,而其他運行器默認不會開啟此功能。- 默認情況下,GitLab Runner運行器將倉庫克隆到
$CI_BUILDS_DIR
目錄下的一個名稱唯一的子目錄中,但有時候你的項目可能需要指定一個特殊的路徑用來保存下載的倉庫,這個時候就可以使用GIT_CLONE_PATH
變量來指定克隆文件的存放目錄。 GIT_CLONE_PATH
必須是$CI_BUILDS_DIR
的子目錄,$CI_BUILDS_DIR
目錄各個運行器可能不同。
我們嘗試在我們的SHELL運行器上去設置 GIT_CLONE_PATH
目錄。
下面是官方給出的一個示例:
1 2 3 4 5 6 |
variables: GIT_CLONE_PATH: $CI_BUILDS_DIR/project-name test: script: - pwd
|
我們仿照這個示例修改 .gitlab-ci.yml
配置文件,並進行提交,修改后的內容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# This file is a template, and might need editing before it works on your project.
# see https://docs.gitlab.com/ce/ci/yaml/README.html for all available options # 定義全局變量 variables: # 數據庫信息 SQLALCHEMY_DATABASE_URI: 'mysql+pymysql://root:root@localhost:3306/bluelog?charset=utf8mb4' # 不發送警告通知 SQLALCHEMY_TRACK_MODIFICATIONS: "False" # 顯示執行SQL SQLALCHEMY_ECHO: "True" # 設置全局構建目錄 GIT_CLONE_PATH: $CI_BUILDS_DIR/global_folder stages: - build - code_check - test - deploy build1: stage: build variables: # 數據庫信息 SQLALCHEMY_DATABASE_URI: 'mysql+pymysql://root:123456@localhost:3306/bluelog?charset=utf8mb4' # 不顯示執行SQL SQLALCHEMY_ECHO: "False" # 設置全局構建目錄 GIT_CLONE_PATH: $CI_BUILDS_DIR/sub_folder script: - pwd - export - echo "Do your build here" - cloc --version - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" tags: - bluelog find Bugs: stage: code_check script: - pwd - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" - SQLALCHEMY_ECHO="Nothing" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" tags: - bluelog test1: stage: test variables: # CKEditor富文本設置 CKEDITOR_SERVE_LOCAL: "True" script: - pwd - echo -e "SQLALCHEMY_DATABASE_URI:${SQLALCHEMY_DATABASE_URI}" - echo -e "SQLALCHEMY_TRACK_MODIFICATIONS:${SQLALCHEMY_TRACK_MODIFICATIONS}" - echo -e "SQLALCHEMY_ECHO:${SQLALCHEMY_ECHO}" - echo -e "CKEDITOR_SERVE_LOCAL:${CKEDITOR_SERVE_LOCAL}" tags: - bluelog test2: stage: test script: - echo "Do another parallel test here" - echo "For example run a lint test" tags: - bluelog deploy1: stage: deploy script: - echo "Do your deploy here" tags: - bluelog
|
提交修改構建目錄后,流水線執行失敗:

查看作業詳情:

可以看到提示 ERROR: Job failed: setting GIT_CLONE_PATH is not allowed, enable `custom_build_dir` feature
意思是說不允許設置 GIT_CLONE_PATH
變量,需要設置 custom_build_dir
屬性。
我們參考 The [runners.custom_build_dir] section 來設置 custom_build_dir
屬性。
我們查看一下GitLab Runner的配置文件內容:
[root@server ~]# cat /etc/gitlab-runner/config.toml concurrent = 1 check_interval = 0 [session_server] session_timeout = 1800 [[runners]] name = "bluelog runner" url = "http://192.168.56.14/" token = "1aXYZ5H9n2y8oauWkz7D" executor = "shell" [runners.custom_build_dir] [runners.cache] [runners.cache.s3] [runners.cache.gcs]
我們參考示例:
[runners.custom_build_dir] enabled = true
開啟 custom_build_dir
屬性,修改后配置文件內容如下:
[root@server ~]# cat /etc/gitlab-runner/config.toml concurrent = 1 check_interval = 0 [session_server] session_timeout = 1800 [[runners]] name = "bluelog runner" url = "http://192.168.56.14/" token = "1aXYZ5H9n2y8oauWkz7D" executor = "shell" [runners.custom_build_dir] enabled = true [runners.cache] [runners.cache.s3] [runners.cache.gcs]
重新觸發”build1”作業,看看效果。
此時可以看到,作業開始運行了,並且在 /root/gitlab-runner/builds
目錄下生成了四個folder相關的目錄:
[root@server builds]# pwd /root/gitlab-runner/builds [root@server builds]# ls -ld *folder* drwxr-xr-x 5 root root 193 Jul 12 23:08 global_folder drwxr-xr-x 3 root root 26 Jul 12 23:08 global_folder.tmp drwxr-xr-x 5 root root 193 Jul 12 23:08 sub_folder drwxr-xr-x 3 root root 26 Jul 12 23:08 sub_folder.tmp
查看”build1”和”find Bugs”作業的詳情:

可以看到”build1”作業使用作業級定義的 GIT_CLONE_PATH: $CI_BUILDS_DIR/sub_folder
,倉庫會被下載到 /root/gitlab-runner/builds/sub_folder
目錄下。

可以看到”build1”作業使用全局級定義的 GIT_CLONE_PATH: $CI_BUILDS_DIR/global_folder
,倉庫會被下載到 /root/gitlab-runner/builds/global_folder
目錄下。
處理並發(Handling concurrency)
-
當執行器配置並發數
concurrent
大於1時,有可能導致作業運行失敗,因為有可能多個作業都運行在相同的目錄上,GitLab Runner運行器並不會去阻止這種情形,管理員和開發人員必須遵守Runner配置的要求。 -
要避免這種情況,您可以在
$CI_BUILDS_DIR
中使用唯一路徑,因為Runner公開了另外兩個提供唯一並發ID的變量:$CI_CONCURRENT_ID
:給定執行程序中運行的所有作業的唯一ID。$CI_CONCURRENT_PROJECT_ID
:在給定執行程序和項目中運行的所有作業的唯一ID。
-
在任何場景和任何執行器中都應該運行良好的最穩定的配置是在
GIT_CLONE_PATH
中使用$CI_CONCURRENT_ID
。
例如:
1 2 3 4 5 6 |
variables: GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_CONCURRENT_ID/project-name test: script: - pwd
|
嵌套路徑(Nested paths)
GIT_CLONE_PATH
變量最多只能擴展一次,不支持嵌套的變量路徑。
下面定義了兩個變量:
1 2 3 |
variables: GOPATH: $CI_BUILDS_DIR/go GIT_CLONE_PATH: $GOPATH/src/namespace/project
|
GIT_CLONE_PATH
變量擴展一次后,變量成了 $CI_BUILDS_DIR/go/src/namespace/project
,這個時候在路徑中有一個變量,而 GIT_CLONE_PATH
變量不會再次擴展 $CI_BUILDS_DIR
導致作業運行失敗。
特殊的YAML功能
可以使用特殊的YAML功能,如錨點( &
),別名( *
)和合並( <<
),這將使您大大降低 .gitlab-ci.yml
的復雜性。
隱藏關鍵字或作業
如果我們想暫時禁用某個作業,我們可以將該作業的所有行都注釋掉,如下示例:
1 2 3 |
#hidden_job: # script: # - run test
|
更好的方法是,我們在作業名稱前面增加一個點號( .
), 這樣GitLab CI流水線就會自動處理忽略掉 .hidden_job
作業。
改成下面這樣:
1 2 3 |
.hidden_job: script: - run test
|
錨點(Anchors)
- 錨點可以讓你容易復制文檔內容,錨點可以用來復制或繼承某些屬性,錨點與隱藏作業一起使用可提供作業模板。
下面的例子使用錨點和合並創建了兩個作業,test1
和 test2
,兩個作業都是繼承自隱藏作業 .job_template
,並且都有他們自己獨有的工作腳本定義:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
.job_template: &job_definition # Hidden key that defines an anchor named 'job_definition' image: ruby:2.1 services: - postgres - redis test1: <<: *job_definition # Merge the contents of the 'job_definition' alias script: - test1 project test2: <<: *job_definition # Merge the contents of the 'job_definition' alias script: - test2 project
|
&
用於設置錨點名稱為job_definition
,也就是給隱藏作業設置一個錨點job_definition
。<<
合並,將錨點定義的模板內容復制到當前作業的當前位置來。*
包含錨點的名稱job_definition
。
擴展后的配置文件變成下面這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.job_template: image: ruby:2.1 services: - postgres - redis test1: image: ruby:2.1 services: - postgres - redis script: - test1 project test2: image: ruby:2.1 services: - postgres - redis script: - test2 project
|
再看另外一個示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
.job_template: &job_definition script: - test project .postgres_services: services: &postgres_definition - postgres - ruby .mysql_services: services: &mysql_definition - mysql - ruby test:postgres: <<: *job_definition services: *postgres_definition test:mysql: <<: *job_definition services: *mysql_definition
|
擴展后是這樣的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
.job_template: script: - test project .postgres_services: services: - postgres - ruby .mysql_services: services: - mysql - ruby test:postgres: script: - test project services: - postgres - ruby test:mysql: script: - test project services: - mysql - ruby
|
可以看到隱藏的關鍵字或者作業可以方便地用作為模板。
Triggers觸發器
- 當使用觸發器令牌觸發流水線運行時,觸發器可用於強制重建特定分支,標記或提交,並使用API調用。
- 觸發器使用可參考 使用流水線觸發器觸發流水線執行 。
忽略CI檢查
- 當你提交的commit日志信息中包含
[ci skip]
或者[skip ci]
(忽略大小寫),提交可以成功但是會忽略流水線的執行。 - 或者,在
git push
時添加推送選項,如git push -o ci.skip
。
我們第一次修改配置文件,commit日志為”移除自定義構建目錄,測試忽略ci構建 ci skip”,包含有 ci skip
關鍵字,但是沒有左右中括號,進行提交:

但是發現流水線被觸發了,正常運行了:

我們第二次修改配置文件,commit日志為”移除自定義構建目錄,測試忽略ci構建 [CI Skip]”,包含有 [CI Skip]
關鍵字,進行提交:

可以發現流水線沒有被觸發,但是提交已經創建成功了:


我們第三次修改配置文件,commit日志為”測試使用git push添加推送選項”,進行提交:

可以發現流水線沒有被觸發,但是提交已經創建成功了:

.gitlab-ci.yml
配置文件各個關鍵字的使用就介紹到這里。
參考:
- Getting started with GitLab CI/CD
- GitLab CI/CD Pipeline Configuration Reference
- Gitlab CI yaml官方配置文件翻譯
- GitLab Runner Advanced configuration
- Why we’re replacing GitLab CI jobs with .gitlab-ci.yml
- GitLab CI/CD Examples
- GitLab CI/CD Variables
- 企業級.gitlab-ci.yml示例
- Gitlab CI 使用高級技巧
- git tag的用法
- Python靜態代碼檢查工具Flake8
- Python代碼規范利器Flake8
- Flake8: Your Tool For Style Guide Enforcement
- 基於GitLab CI搭建Golang自動構建環境
- 什么是staging server
- Cache dependencies in GitLab CI/CD
- Introduction to job artifacts
- dependencies
- JUnit test reports
- include
- extends
- GitLab Pages
- Priority of environment variables
- The [runners.custom_build_dir] section
- trigger
- Using Git submodules with GitLab CI
- Shallow cloning