参考文档:
.gitlab-ci.yml说明
Gitlab CI 使用高级技巧
GitLabPipeline语法--GitLabCI系列之流水线语法
官方文档

1. GitLab Runner

一般来说,构建任务都会占用很多的系统资源 (譬如编译代码),而 GitLab CI 又是 GitLab的一部分,如果由 GitLab CI 来运行构建任务的话,在执行构建任务的时候,GitLab 的性能会大幅下降。

GitLab CI 最大的作用是管理各个项目的构建状态,因此,运行构建任务这种浪费资源的事情就交给 GitLab Runner 来做啦。因为 GitLab Runner 可以安装到不同的机器上,所以在构建任务运行期间并不会影响到 GitLab 的性能。

GitLab Runner的安装特别简单,官网有各平台的安装方法或安装包,此处不再赘述。

2. Stages

Stages 表示构建阶段,说白了就是上面提到的流程。默认有3个 stages:build, test, deploy。我们可以在一次 Pipeline 中定义多个 Stages,这些 Stages 会有以下特点:

  • 所有 Stages 会按照顺序运行,即当一个 Stage 完成后,下一个 Stage 才会开始
  • 同一阶段的作业并行运行
  • 只有当所有 Stages 完成后,该构建任务 (Pipeline) 才会成功
  • 如果任何一个 Stage 失败,那么后面的 Stages 不会执行,该构建任务 (Pipeline) 失败

.pre 和 .post

两个特殊的阶段,.pre 始终是整个管道的第一个运行阶段,.post 始终是整个管道的最后一个运行阶段。 用户定义的阶段都在两者之间运行。.pre.post的顺序无法更改。如果管道仅包含.pre.post阶段的作业,则不会创建管道。

若 job 中的 stage ,未在 stages 定义,则会作为 .pre

3. Jobs

Jobs 表示构建工作,表示某个 Stage 里面执行的工作。我们可以在 Stages 里面定义多个 Jobs,这些 Jobs 会有以下特点:

1、相同 Stage 中的 Jobs 会并行执行

2、相同 Stage 中的 Jobs 都执行成功时,该 Stage 才会成功

3、如果任何一个 Job 失败,那么该 Stage 失败,即该构建任务 (Pipeline) 失败

4. .gitlab-ci.yml

4.1 介绍

.gitlab-ci.yml 用来配置 CI 用你的项目中做哪些操作,这个文件位于仓库的根目录。

当有新内容 push 到仓库,或者有代码合并后,GitLab会查找是否有.gitlab-ci.yml文件,如果文件存在,Runners 将会根据该文件的内容开始 build 本次 commit。

.gitlab-ci.yml 使用 YAML 语法, 你需要格外注意缩进格式,要用空格来缩进,不能用 tabs 来缩进。

4.2 约束

任务中必须得有 script 部分。

4.3 示例

# 全局配置使用的镜像
image: xx:1.0

# 定义 stages(阶段)。任务将按此顺序执行。
stages:
  - build
  - test
  - deploy

# 定义 job(任务)
job1:
  stage: test
  tags:
    - XX #只有标签为XX的runner才会执行这个任务
  only:        
    - dev    #只有dev分支提交代码才会执行这个任务。也可以是分支名称或触发器名称
    - /^future-.*$/ #正则表达式,只有future-开头的分支才会执行
  script:
    - echo "I am job1"
    - echo "I am in test stage"

# 定义 job
job2:
  stage: test    #如果此处没有定义stage,其默认也是test
  only:
    - master    #只有master分支提交代码才会执行这个任务
  script:
    - echo "I am job2"
    - echo "I am in test stage"
  allow_failure: true #允许失败,即不影响下步构建    

# 定义 job
job3:
  stage: build
  except:    
    - dev #除了dev分支,其它分支提交代码都会执行这个任务
  script:
    - echo "I am job3"
    - echo "I am in build stage"    
  when: always #不管前面几步成功与否,永远会执行这一步。它有几个值:on_success (默认值)\on_failure\always\manual(手动执行)
    
# 定义 job
.job4:    #对于临时不想执行的job,可以选择在前面加个".",这样就会跳过此步任务,可以不用注释
  stage: deploy
  script:
    - echo "I am job4"    

# 模板,相当于公用函数,有重复任务时很有用,YAML 的语法
.job_template: &job_definition  # 创建一个锚,'job_definition'
  image: ruby:2.1
  services:
    - postgres
    - redis

test1:
  <<: *job_definition           # 利用锚'job_definition'来合并
  script:
    - test1 project

#下面几个都相当于全局变量,都可以添加到具体job中,这时会被子job的覆盖    

before_script:
  - echo "每个job之前都会执行"    
  
after_script:
  - echo "每个job之后都会执行"    
  
variables:    #变量
  DATABASE_URL: "postgres://postgres@postgres/my_database"  #在job中可以用${DATABASE_URL}来使用这个变量。常用的预定义变量有CI_COMMIT_REF_NAME(项目所在的分支或标签名称),CI_JOB_NAME(任务名称),CI_JOB_STAGE(任务阶段)
  GIT_STRATEGY: "none" #GIT策略,定义拉取代码的方式,有3种:clone/fetch/none,默认为clone,速度最慢,每步job都会重新clone一次代码。我们一般将它设置为none,在具体任务里设置为fetch就可以满足需求,毕竟不是每步都需要新代码,那也不符合我们测试的流程

cache:    #缓存
  #因为缓存为不同管道和任务间共享,可能会覆盖,所以有时需要设置key
  key: ${CI_COMMIT_REF_NAME}  # 启用每分支缓存。
  #key: "$CI_JOB_NAME/$CI_COMMIT_REF_NAME" # 启用每个任务和每个分支缓存。需要注意的是,如果是在windows中运行这个脚本,需要把$换成%
  untracked: true    #缓存所有Git未跟踪的文件
  paths:    #以下2个文件夹会被缓存起来,下次构建会解压出来
    - node_modules/
    - dist/

可以通过 gitlab 中的 lint 验证是否有语法错误

4.4 跳过 jobs

如果你的 commit 信息包涵 [ci skip] 或者 [skip ci],不论大小写,这个 commit 将会被创建,但是 job 会被跳过。

5. 关键字

5.1 gitlan-ci 关键字

关键字是否必须描述
imageno使用的docker镜像。详见
servicesno使用的docker服务。详见
stagesno定义构建场景
typesnostages的别名(不赞成使用)
before_scriptno定义每个任务的脚本启动前所需执行的命令
after_scriptno定义每个任务的脚本执行结束后所需执行的命令
variablesno定义构建变量
cacheno定义哪些文件需要缓存,让后续执行可用

5.2 Job 关键字

关键字是否必须描述
scriptyesRunner执行的命令或脚本。可以包含多条命令
imageno使用的docker镜像。详见
servicesno使用的docker服务。详见
stageno定义job stage(默认:test)
typenostage的别名(已弃用)
variablesno定义job级别的变量
onlyno定义一列git分支,并为其创建job
exceptno定义一列git分支,不创建job
tagsno定义一列tags,用来指定选择哪个Runner(同时Runner也要设置tags)
allow_failureno允许job失败。失败的job不影响commit状态
whenno定义何时开始job。可以是on_success,on_failure,always或者manual
dependenciesno定义job依赖关系,这样他们就可以互相传递artifacts
cacheno定义应在后续运行之间缓存的文件列表
before_scriptno重写一组在作业前执行的命令
after_scriptno重写一组在作业后执行的命令
environmentno定义此作业完成部署的环境名称
coverageno定义给定作业的代码覆盖率设置

5.3 only and except 关键字

关键字描述
branches当一个分支被push上来
tags当一个打了tag的分支被push上来
api当一个pipline被piplines api所触发调起,详见piplines api
external当使用了GitLab以外的CI服务
pipelines针对多项目触发器而言,当使用CI_JOB_TOKEN并使用gitlab所提供的api创建多个pipelines的时候
pushes当pipeline被用户的git push操作所触发的时候
schedules针对预定好的pipline而言(每日构建一类)
triggers用token创建piplines的时候
web在GitLab页面上Pipelines标签页下,你按了run pipline的时候

6. artifact 和 dependencies

artifact

用于指定在作业成功或者失败时应附加到作业的文件或目录的列表。作业完成后,工件将被发送到GitLab,并可在GitLab UI中下载。

同时 artifacts 还可被用于在传递给下一个 job ,如果要在两个 job 之间传递 artifacts,你必须设置dependencies,下面有几个例子

test-job1:
  stage: test
  script:
    - pwd
    - mkdir target
    - touch target/a.txt
    - echo "e" > target/a.txt
    - echo "This job tests something"
  artifacts:
    paths:
      - target/

deploy-prod:
  dependencies:
    - test-job1
  stage: deploy
  script:
    - echo "This job deploys something from the $CI_COMMIT_BRANCH branch. no"
    - ls target

paths 路径是相对于项目目录的,不能直接链接到项目目录之外。

test stage 输出如下

$ pwd
/builds/TPpuvHCc/0/yanglongqi/test
$ mkdir target
$ touch target/a.txt
$ echo "e" > target/a.txt
$ echo "This job tests something"
This job tests something

deploy 输出如下

$ echo "This job deploys something from the $CI_COMMIT_BRANCH branch. no"
This job deploys something from the master branch. no
$ ls target
a.txt