由于负责小组的 CI 公共事项,经常需要配置 CI 流程,或者帮助其他人解决一些问题,整理了一下常用的 CI 脚本,以方便查阅。
1. .gitlab-ci.yml
结构
下面是, GitLab CI 的配置文件结构。
.gitlab-ci.yml
文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # 一些前置脚本,完成激活环境等操作
before_script:
- source /data/runner/node/bin/activate
- which node && node --version
- which npm && npm --version
- LANG="zh_CN.utf8"
- export LC_ALL=zh_CN.UTF-8
# 编排需要执行的 stage
stages:
- build
- deploy
# 定义 job。job 属于某一个 stage,比如这里的 build 、deploy。GitLab CI 会按照 stages 配置的先后,顺序执行每一个 stage。
|
2. 编译 Webpack 工程并提交到 GitLab 仓库
这里约定:
- 前端工程在根目录的 webpack 目录下
- 前端工程编译之后的输出文件在根目录的 static/dist 目录下
- 前端的编译命令是
npm run build
GitLab CI 内置变量可以去 这里 查看。也可以,使用关键字 variables
定义自己的变量。比如,上面的目录路径,就可以配置为变量。但是每个项目有其独特性,这里就没有写成通用的形式,避免误导。
通常,我会将一些账户信息配置在 settings/ci_cd
页面,并将这些变量勾选保护。勾选保护之后,只有受保护的分支才能够获取到这些变量,也就是下面的 GIT_USERNAME
、GIT_PASSWORD
这部分。
这里强烈建议,不要直接在当前代码目录直接提交 Git,应该将代码重新拉一份到本地,以保证环境不被污染。
.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
| stages:
- build
build-webpack:
stage: build
variables:
CI_REPOSITORY_URL:
http://$GIT_USERNAME:$GIT_PASSWORD@gitlab.yourdomain.com/$CI_PROJECT_PATH.git
cache:
untracked: true
paths:
- webpack/node_modules
script:
- echo "start build and commit"
- cd webpack
# 可通过关键字优化
- npm install
# 可通过关键字优化
- npm run build
- cd ..
- rm -rf git-dir
- git clone -b $CI_COMMIT_REF_NAME http://$GIT_USERNAME:$GIT_PASSWORD@gitlab.yourdomain.com/$CI_PROJECT_PATH.git git-dir
- cd git-dir && rm -rf ./static/dist
- mv ../static/dist static/
- git config --global user.name $GITLAB_USER_NAME
- git config --global user.email $GITLAB_USER_EMAIL
- git add static/dist
# 避免循环构建
- git commit -m "auto commit [ci skip]`git log -1 --pretty=%B`" || exit 0
- git push $CI_REPOSITORY_URL $CI_COMMIT_REF_NAME >/dev/null 2>&1 || exit 0
- echo "end build and commit"
tags:
# 指定 runner
- linux
- shell
only:
# 指定分支
- master
|
3. 从 GitLab 推送代码到 SVN 仓库
由于发布系统采用的是 SVN 仓库,但是 Git 更适合多人开发协助,在开发的过程中使用的是 GitLab 仓库。
为了将 GitLab 仓库自动推送到 SVN 仓库,可以使用下面这个 job:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| push-to-svn:
stage: deploy
variables:
CI_REPOSITORY_URL:
http://$GIT_USERNAME:$GIT_PASSWORD@gitlab.yourdomain.com/$CI_PROJECT_PATH.git
script:
- echo "start push to svn"
- echo "step 1/3: git clone"
- git clone -b $CI_COMMIT_REF_NAME $CI_REPOSITORY_URL git-dir
- echo "finished"
- echo "setp 2/3: svn checkout"
- echo 't' | svn checkout $SVN_PATH svn-dir --username $SVN_USERNAME --password $SVN_PASSWORD --no-auth-cache
- echo "finshed"
- echo "step 3/3: push git master to svn trunk"
# 确保删除文件操作有效,可优化
- cd svn-dir && svn delete *
- rsync -avq git-dir/ svn-dir/
- cd ./svn-dir
- svn add * --force
- echo 't' | svn commit -m "`git log -1 --pretty=%B`" --username $SVN_USERNAME --password $SVN_PASSWORD --no-auth-cache
- echo "end push to svn"
|
4. 通过关键字控制执行的脚本
GitLab CI 提供了一些内置关键字用于控制 CI 的行为。比如,在提交信息中增加 [ci skip]
或 [skip ci]
就会跳过当次提交触发的 CI 构建。
受到这种想法的启发,我们也可以在脚本中,从提交信息中匹配一些关键字,用于控制脚本执行逻辑。
- 通过是否有关键字
[install]
,判断是否执行依赖包的安装
1
| if [[ $(git log -1 --pretty=%B) = *"["*"install"*"]"* ]]; then npm install; else echo "not npm install"; fi;
|
- 通过是否有关键字
[build]
,判断是否进行前端的打包
1
| if [[ $(git log -1 --pretty=%B) = *"["*"build"*"]"* ]]; then npm run build; else echo "not npm install"; fi;
|
- 通过是否有关键字
[delete]
,判断在执行 SVN 推送时,是否需要删除文件。这里主要是由于 svn add *
命令不能将删除的文件提交,删除文件必须使用 svn delete
处理。如果不使用 svn delete
命令,会导致 GitLab 中被删除的文件,在 SVN 中实际上没有被删除。
1
| if [[ $(git log -1 --pretty=%B) = *"["*"delete"*"]"*]]; then cd svn-dir && svn delete * && cd ..; else echo "not svn delete"; fi;
|
5. 从 yml 获取变量
yml 文件格式:
1
2
3
4
| code: test
name: 测试
author: admin
version: 1.2.3
|
以上面的 yml 格式为例,需要获取相关字段信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| parse_yaml() {
local prefix=$2
local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=$(echo @|tr @ '\034')
sed -ne "s|^\($s\)\($w\)$s:$s\"\(.*\)\"$s\$|\1$fs\2$fs\3|p" \
-e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|p" $1 |
awk -F$fs '{
indent = length($1)/2;
vname[indent] = $2;
for (i in vname) {if (i > indent) {delete vname[i]}}
if (length($3) > 0) {
vn=""; for (i=0; i<indent; i++) {vn=(vn)(vname[i])("_")}
printf("%s%s%s=\"%s\"\n", "'$prefix'",vn, $2, $3);
}
}'
}
eval $(parse_yaml test.yml "config_")
|
通过执行上面的脚本,可以获取到 test.yml 中的字段信息。
1
2
3
| echo ${config_code}
echo ${config_name}
...
|
6. 将环境变量值,写到 yml 文件
yml 文件格式:
1
2
3
4
| code: test
name: 测试
author: admin
version: 1.2.3
|
以上面的 yml 格式为例,获取环境变量中的 VER
值,并将其写到 version:
后面中。
1
| sed -i "/version:/s/[0-9].*$/${VER}/g" test.yml
|