深入浅出FE(十六)深入浅出YAML
Posted Fentech
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入浅出FE(十六)深入浅出YAML相关的知识,希望对你有一定的参考价值。
YAML 并不是一种新奇的语言,YAML 首次发表于 2001 年,距离现在已经过去差不多 20 个年头。YAML 虽然不如 JSON、XML 之类的语言流行,应用也没有那么广泛,但是 YAML 也有它的优势。
一、简介
YAML 是一种较为人性化的数据序列化语言,可以配合目前大多数编程语言使用。
YAML 的语法比较简洁直观,特点是使用空格来表达层次结构,其最大优势在于数据结构方面的表达,所以 YAML 更多应用于编写配置文件,其文件一般以 .yml 为后缀。
YAML 目前的官方全称为 “ YAML Ain't Markup Language(YAML 不是标记语言)”,但有意思的是,其实 YAML 最初的含义是 “ Yet Another Markup Language(还是一种标记语言)”。
目前 YAML 的最新版本为 1.2(第三个版本),本文将以 YAML 1.2 的标准进行讲解。
二、基本语法
大小写敏感
- 就是字面上的意思
One: 1
one: 2
用缩进表示层级关系
- 缩进只能使用空格,不能用 TAB 字符
- 缩进的空格数量不重要,但是同一层级的元素左侧必须对齐
# YAML
one:
two: 2
three:
four: 4
five: 5
// 以上的内容转成 JSON 后
"one":
"two": 2,
"three":
"four": 4,
"five": 5
用 # 表示注释
- 只支持单行注释
# 我是注释
# 我也是注释
一个文件中可以包含多个文件的内容
- 用“ --- ”即三个破折号表示一份内容的开始
- 用“ ... ”即三个小数点表示一份内容的结束(非必需)
---
# 这是第一份内容
one: 1
# 其他内容...
...
---
# 这是第二份内容
two: 2
# 其他内容...
数据结构与类型
对象(Mapping)
表示以键值对(key: value)形式出现的数据
- 使用“冒号+空格”来分开键与值
# YAML
key: value
// JSON
"key": "value"
- 支持多层嵌套(用缩进表示层级关系)
# YAML
key:
child-key1: value1
child-key2: value2
// JSON
"key":
"child-key1": "value1",
"child-key2": "value2",
- 支持流式风格( Flow style)的语法(用花括号包裹,用逗号加空格分隔,类似 JSON)
# YAML
key: child-key1: value1, child-key2: value2
// JSON
"key": "child-key1": "value1", "child-key2": "value2"
- 使用问号“?”声明一个复杂对象,允许你使用多个词汇(数组)来组成键
# YAML
?
- keypart1
- keypart2
:
- value1
- value2
数组(Sequence)
- 一组以区块格式(Block Format)(即“破折号+空格”)开头的数据组成一个数组
# YAML
values:
- value1
- value2
- value3
// JSON
"values": [ "value1", "value2", "value3" ]
- 同时也支持内联格式(Inline Format)来表达(用方括号包裹,逗号加空格分隔,类似 JSON)
# YAML
values: [value1, value2, value3]
// JSON
"values": [ "value1", "value2", "value3" ]
- 支持多维数组(用缩进表示层级关系)
# YAML
values:
-
- value1
- value2
-
- value3
- value4
// JSON
"values": [ [ "value1", "value2"], ["value3", "value4"] ]
标量(Scalars)
表示 YAML 中最基本的数据类型
字符串(String)
- 字符串一般不需要用引号包裹,但是如果字符串中使用了反斜杠“\\”开头的转义字符就必须使用引号包裹
# YAML
strings:
- Hello without quote # 不用引号包裹
- Hello
world # 拆成多行后会自动在中间添加空格
- 'Hello with single quotes' # 单引号包裹
- "Hello with double quotes" # 双引号包裹
- "I am fine. \\u263A" # 使用双引号包裹时支持 Unicode 编码
- "\\x0d\\x0a is \\r\\n" # 使用双引号包裹时还支持 Hex 编码
- 'He said: "Hello!"' # 单双引号支持嵌套"
// JSON
"strings":
[ "Hello without quote",
"Hello world",
"Hello with single quotes",
"Hello with double quotes",
"I am fine. ☺",
"\\r\\n is \\r\\n",
"He said: 'Hello!'" ]
- 对于多行的文字,YAML 提供了两种特殊的语法支持
保留换行(Newlines preserved)
使用 竖线符“ | ”来表示该语法,每行的缩进和行尾空白都会被去掉,而额外的缩进会被保留
# YAML
lines: |
我是第一行
我是第二行
我是吴彦祖
我是第四行
我是第五行
// JSON
"lines": "我是第一行\\n我是第二行\\n 我是吴彦祖\\n 我是第四行\\n我是第五行"
折叠换行(Newlines folded)
使用 右尖括号“ > ”来表示该语法,只有空白行才会被识别为换行,原来的换行符都会被转换成空格
# YAML
lines: >
我是第一行
我也是第一行
我仍是第一行
我依旧是第一行
我是第二行
这么巧我也是第二行
// JSON
"lines": "我是第一行 我也是第一行 我仍是第一行 我依旧是第一行\\n我是第二行 这么巧我也是第二行"
布尔值(Boolean)
- “true”、“True”、“TRUE”、“yes”、“Yes”和“YES”皆为真
- “false”、“False”、“FALSE”、“no”、“No”和“NO”皆为假
# YAML
boolean:
- true # True、TRUE
- yes # Yes、YES
- false # False、FALSE
- no # No、NO
// JSON
"boolean": [ true, true, false, false ]
整数(Integer)
- 支持二进制表示
# YAML
int:
- 666
- 0001_0000 # 二进制表示
// JSON
"int": [ 666, 4096 ]
浮点数(Floating Point)
- 支持科学计数法
# YAML
float:
- 3.14
- 6.8523015e+5 # 使用科学计数法
// JSON
"float": [ 3.14, 685230.15 ]
空(Null)
- “null”、“Null”和“~”都是空,不指定值默认也是空
# YAML
nulls:
- null
- Null
- ~
-
// JSON
"nulls": [ null, null, null, null ]
时间戳(Timestamp)
- YAML 也支持 ISO 8601 格式的时间数据
这里使用 javascript 对象进行对比
# YAML
date1: 2020-05-26
date2: 2020-05-26T01:00:00+08:00
dete3: 2020-05-26T02:00:00.10+08:00
date4: 2020-05-26 03:00:00.10 +8
// JavaScript
date1: Tue May 26 2020 08:00:00 GMT+0800 (中国标准时间),
date2: Tue May 26 2020 01:00:00 GMT+0800 (中国标准时间),
dete3: Tue May 26 2020 02:00:00 GMT+0800 (中国标准时间),
date4: Tue May 26 2020 03:00:00 GMT+0800 (中国标准时间)
类型转换
- YAML 支持使用严格类型标签“!!”(双感叹号+目标类型)来强制转换类型
# YAML
a: !!float '666' # !! 为严格类型标签
b: '666' # 其实双引号也算是类型转换符
c: !!str 666 # 整数转为字符串
d: !!str 666.66 # 浮点数转为字符串
e: !!str true # 布尔值转为字符串
f: !!str yes # 布尔值转为字符串
// JSON
"a": 666,
"b": "666",
"c": "666",
"d": "666.66",
"e": "true"
"f": "yes"
其他高级类型
YAML 也可以使用一些更高级的类型,但是并不一定兼容所有解析器,包括集合(Sets)、有序映射(Ordered Map)、十六进制数据(Hexdecimal)和二进制数据(Binary)。
本文将不会对这几种类型进行讲解,感兴趣的读者可以自行搜索研究。
数据重用与合并
- 为了保持内容的简洁,避免过多重复的定义,YAML 提供了由锚点标签“&”和引用标签“*”组成的语法,利用这套语法可以快速引用相同的一些数据...
# YAML
a: &anchor # 设置锚点
one: 1
two: 2
three: 3
b: *anchor # 引用锚点
// JSON
"a":
"one": 1,
"two": 2,
"three": 3
,
"b":
"one": 1,
"two": 2,
"three": 3
- 配合合并标签“<<”使用可以与任意数据进行合并,你可以把这套操作想象成面向对象语言中的继承...
# YAML
human: &base # 添加名为 base 的锚点
body: 1
hair: 999
singer:
<<: *base # 引用 base 锚点,实例化时会自动展开
skill: sing # 添加额外的属性
programer:
<<: *base # 引用 base 锚点,实例化时会自动展开
hair: 6 # 覆写 base 中的属性
skill: code # 添加额外的属性
// JSON
"human": "body": 1, "hair": 999 ,
"singer": "body": 1, "hair": 999, "skill": "sing" ,
"programer": "body": 1, "hair": 6, "skill": "code"
相关资料
- YAML 官方网站https://yaml.org
- YAML 1.2 官方文档https://yaml.org/spec/1.2/spec.html
- YAML - 维基百科https://zh.wikipedia.org/wiki/YAML
- YAML to JSON (格式在线转换)https://www.json2yaml.com/convert-yaml-to-json
三、YAML用法
- stages
- cache
- only
- when
- before_script,script, after_script
- artifacts
- hidden_job && extends
- reserved keywords - include
stages:
stages是用来定义一个pipeline的,一个pipeline就像一个流水线,由一系列job来构成。比如在发布(publish)之前要做lint,test,build,那么这四个job就构成一个pipeline,写成下面的样子:
stages
- lint
- test
- build
- publish
然后你在gitlab的pipeline下面就能看到下面的图:
上面我们虽然定义了一个pipeline,和4个job名称,但是具体每个job做什么还是不清楚的,接下来我们学习怎么定义一个job。
job
以上面的lint为例,我们需要执行npm run lint
命令来查看有没有lint错误,那么这个job可以写成:
job-lint:
stage: lint
script: npm run lint
这里job-lint
是任务名称,script
是要在终端执行的命令,stage
表示这个job属于哪个stage(pipeline的某个节点)。job名称这里要注意一点是,不能使用保留字,比如:不能把一个job的名字称为stages或者image,就像变量名不能用if一样。相关文档可以看这里。
一个stage下可以有多个job,比如:打包的时候要打包到windows,mac,linux下,可以这样:
job-build-mac:
stage: build
job-build-win;
stage: build
job-build-linux:
stage: build
有时候,我们希望一些任务是在某些场景下执行的,比如:打tag的时候再build,这时候可以使用only/except。
variables
在跑一个job的过程中,我们可能会需要环境变量,比如development,production,一个url,又或者是一个不希望显示在控制台的token,都可以作为一个环境变量,设置一个环境变量通常有3种方式:在项目设置中,在yml文件中,或者通过api。
通过项目设置界面来配置环境变量的入口如下:
在variables下可以配置变量名和值,通常是需要保密的变量
当然我们也可以设置在yml中:
variables:
TEST: "HELLO WORLD"
然后就可以在脚本中引用:
script:
- echo $TEST
only/except
以上面的场景为例,我们可以这样写job-build:
job-build:
stage: build
script: npm run build
only:
- tags
这样,上面的job就只有在我们push tags时才会触发。如果我们希望一个job只在某一类分支有提交的时候触发,可以这样:
job-bugfix-build:
stage: build
script: npm run build
only:
- /^bugfix-.+$/
上面这个例子只有在bugfix为前缀的分支产生提交的时候,才会触发job-bugfix-build。
然而,这样并不足以让这个任务跑起来,因为CI是跑在docker里面的,在执行run lint之前,我们需要把node环境搭起来,这就需要image保留字了:
image: node:12.18
添加了image之后,在任务开始之前,还要安装依赖,我们使用before_script来完成这件事:
# 使用node镜像
image: node:12.18
# 安装依赖
before_script:
- npm install
有时候我们希望在某些场景下不执行某项任务,这时可以使用expect,比如不对hotfix进行lint:
job-lint-except-hotfix:
script:
- npm run lint
except: /^hotfix-.+$/
when
说了only,再说说when,when
是用来决定当前置任务失败时,当前job是否执行,以及如何执行的问题。比如我们希望lint成功了再执行build:
build_job:
when: on_success
stage: build
needs: lint_job
再比如我们在执行发布的时候,希望手动点击发布按钮来执行发布:
publish_job:
when: manual
stage: publish
script: npm run deploy
artifacts
在前面提到的build job中,我们会使用webpack生成压缩,混淆后的代码,此时我们需要把它保存或者下载下来,这时就要用到artifacts了。用法如下:
build_job:
script: npm run build
artifacts:
name: "$CI_COMMIT_REF_NAME"
paths: dist/
artifacts最终会被打包成一个压缩文件,这里的path表示要添加到压缩文件的文件或文件夹,name表示生成的压缩文件的名字。然后在对应的任务详情特面就可以下载:
include
正如通过程序通过模块来实现代码复用一样,CI的yml配置可以通过include实现配置复用:
include:
- remote: 'https://gitlab.com/awesome-project/raw/master/.before-script-template.yml'
- local: '/templates/.after-script-template.yml'
- template: Auto-DevOps.gitlab-ci.yml
这样,我们可以把一些公用的环境变量或者job放到一个公共repo中,然后在其他项目中通过remote
来引用。
最后,github actions与gitlab ci在概念上很相似,不过配置的写法不太一样,官方还贴心的出了迁移文档:migrating-from-gitlab-cicd-to-github-actions
四、实例:
variables:
DOCKER_DRIVER: overlay2
DOCKER_HOST: tcp://localhost:8888
.dind service: &dind_service
- alias: docker
name: ...
command:
- --insecure-registry=....
cache:
key: node-modules
paths:
- ./node_modules
stages:
- install
- build
- image
install dependency:
stage: install
image: ...
script:
- npm config set registry 仓库地址
- sudo npm install
npm build:
stage: build
image: ...
script:
- sudo npm run build
- sudo takill node
artifacts:
name: "$CI_COMMIT_SHORT_SHA"
paths:
- build
build images:
build: image
image: ...
services: *dind_service
script:
- cp /opt/frontend/Dockerfile
- docker build ...
- docker push ...
dependencies:
- npm build
tags:
- docker
only:
refs:
- /^master/
- /^qa/
- /^dev/
variables:
- $CI_COMMIT_MESSAGE =~ /^build/
上面的YAML文件大致意思为:一旦分支为master 、 qa 、 dev开头有提交信息为build开头的提交会触发build这个job
参考:
https://gitlab.com/help/ci/yaml/README
以上是关于深入浅出FE(十六)深入浅出YAML的主要内容,如果未能解决你的问题,请参考以下文章