0%

2020-05-31 记一次使用 CI 的开源项目开发

2020-05-31 记一次使用 CI 的开源项目开发

项目地址:https://github.com/CaoMeiYouRen/super-search-hub

本项目开源在 GitHub 上。因为 travis-cidocker 都只对开源项目免费,索性就直接开源了。

项目本身倒是没必要多提,本次还是想聊聊持续集成的那些事情。

dependabot

dependabot是 GitHub 推出的一个提醒依赖更新机器人,当你项目的依赖有更新的时候就会自动推送一个 Pull requests

travis-ci

travis-ci 是一个知名的 CI 工具,只需要在项目根目录下编写 .travis.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
language: node_js
node_js: 12.15.0
services:
- docker
install:
- npm install
script:
- npm run lint
- npm run build
deploy:
provider: script
skip_cleanup: true
on:
branch: master
script:
- npm run release
cache:
directories:
- node_modules
notifications:
webhooks:
urls:
# 钉钉
- secure: pCBLuzxjzjdLTHZhse4z66lQJsyrklML1lPfwZSQfgBJLMteyrY9bXqH0uXxzw7UpnFvFQRZjOanDQh+78M1U43PoXzGzONcRc8FTMOSGgCiLd7w7ZNaKaBP+uCzvnS2Y0uHZpZcb0QxCvLTBMQGpO6NztcDTYAoVmWtok0/IwNdHI45Bh4kefNT5L9WE2M09R9J7dLI42feHzNyf7iSHEEJTOi7V5v++FdnRzdA+Vy/UtESpN4RviAJ4E/FXMQhuJ6ili9w/P4qPBJyMTtn9XxRmkSXP+UIwWNoojl/UcbnAKFVywcQzQkyfqe4grz1xmeyoSDX/PopMwpok+/N7pBY4/UWz8k16GlISOifME5MfZ/SHhP5BS/yYV5Pih8iHwMaM0gqXIo2nuBVdBF7pB3058zbIovM0v2FSg3wV2z+4PLeS4UsWaxt5Iqpq0YoWvkOmCMB8aqP1acqCKplkqNw3sU3WJ7mIU8xTd9U5PPYGHeF86h+BLMdz8nYHI8n8n1muKUMaW8MZ4G7jLlOX31Fx07VVjAOAhj0rWAz9qVOKjZFhFh+HmaBgY84zR6zQzZnNtD42vsaNrbKkXsOIrc7cSDdAkkM/7xUeOl+Y0Inr5ElALTpKz5oem7P0M1AN2Z/IAYVYuI9Sre0uFEsbnPbGZ54c7s5/k2r4WFztMk=

在这里着重要提的就是加密配置中的关键字段了。

需要先下载 travis-cli ,下载方式见文档。需要 Ruby 环境,自行下载即可。

1
2
gem install travis
travis version #检查是否安装成功

另外,gem 在国内访问也是慢的要死,配置一下国内镜像即可

接下来就是登陆了

1
travis login --com

此处有一个惊天大坑,那就是 travis-ci.com、travis-ci.org 是同一家公司的两个网站。本来是一个用于商用,一个用于开源,但后来合并了,目前使用的是 travis-ci.com。

但是登陆时默认使用的是 api.travis-ci.org 而不是 api.travis-ci.com 因此需要添加 --com来切换源

后面的看文档就行了

1
travis encrypt FOO=bar #FOO=bar就是要加密的东西

使用时添加为- secure字段就行

semantic-release

本项目的 release 部分使用了 semantic-release。这是一个挺好用的 release 工具

只需要在项目根目录下新建一个 .releaserc.js 文件即可,例如

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
module.exports = {
plugins: [
[
'@semantic-release/commit-analyzer', // 解析git commit,如果要自动生成日志那么是必须的
{
config: 'conventional-changelog-cmyr-config',
},
],
[
'@semantic-release/release-notes-generator', // 生成 git release
{
config: 'conventional-changelog-cmyr-config',
},
],
[
'@semantic-release/changelog', //生成更新日志
{
changelogFile: 'CHANGELOG.md', //日志路径
changelogTitle: '# super-search-hub', //日志标题
},
],
'@semantic-release/npm', //如果是npm模块建议引入,可以自动更新版本号。如果要自动发布则需要NPM_TOKEN
'@semantic-release/github', //需要 GH_TOKEN 来验证权限
[
'@semantic-release/git', // 推送生成的文件回到GitHub。
{
assets: [
'dist',
"docs",
'CHANGELOG.md',
'package.json',
],
},
],
[
'@semantic-release/exec', //执行 release 命令
{
prepareCmd: 'npm run docs:build && docker build -t caomeiyouren/super-search-hub .',
},
],
[
'semantic-release-docker', // 发布到docker。需要配置 DOCKER_USERNAME 和DOCKER_PASSWORD。在travis网站上配置环境变量就行
{
name: 'caomeiyouren/super-search-hub',
},
],
],
}

cz-conventional-changelog

包括 commitizen、cz-conventional-changelog、conventional-changelog-cli、conventional-changelog-cmyr-config。最后一个是日志格式,可以自定义。

下面来具体说明下如何实现自动化生成日志。

首先,要生成日志,那么必须对 git commit 做风格约束。因此使用 commitizen、cz-conventional-changelog 来提交日志。

在 package.json 文件中配置

1
2
3
4
5
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}

之后使用 git cz 即可提交符合要求的 git commit

除此之外,为了防止有人不按规矩来,使用 husky、validate-commit-msg 来校验提交的 git commit 是否符合格式

当提交完 git commit 后,执行

1
conventional-changelog -p cmyr-config -i CHANGELOG.md -s -r 0

来生成日志。

当然如果使用了 CI 就没有这一步了,生成日志这种活也应该交给 CI

jenkins

本项目还有一个需求,那就是当 travis-ci 编译完成后通知自己的服务器进行部署。

自建的 CI 选择了 jenkins,jenkins 也提供了 webhook 来触发部署。

但在这里遇到了一个问题。

最新版的 jenkins 对于 CSRF (跨站请求伪造) 进行了防护,请求中必须带有 crumb 才行,直接访问是 403 的。

经过一番搜寻后找到了解决方法。既然无法直接访问的话那就自己写个中转吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
async function jenkinsAPI(url: string, query: any = {}, data: any = {}, method: any = 'GET') {
const jenkinsAxios = axios.create({
baseURL: 'https://xxx.yyy.zzz',
auth: {
username: JENKINS.JENKINS_USERNAME,
password: JENKINS.JENKINS_PASSWORD,
},
})

const crumbIssuer = await jenkinsAxios.get('/crumbIssuer/api/json')
const result = await jenkinsAxios(url, {
method,
params: query,
data,
headers: {
'Content-Type': 'application/json',
[crumbIssuer.data?.crumbRequestField]: crumbIssuer.data?.crumb,
Cookie: crumbIssuer.headers['set-cookie'][0],
},
timeout: 10000,
})
return result
}

调用这个函数即可

webpack

本项目使用 webpack 来打包,生成的 dist 文件只需要有 node 环境就能运行,无需安装任何依赖。再结合 docker 技术,就生成了一个体积极小的镜像。主要体积是 node.js 这个运行时,代码部分极小

docker

docker 在本项目中用于部署。

话说回来,既然本项目已经使用 webpack 来打包了,只有一个 dist/index.js 文件用于部署,可以讲是非常方便了,那么为什么还是要用 docker?

要说原因的话还是因为 docker 部署比真机部署更加方便,更新起来也更加方便。

同时 docker 部署下运行环境都是一致的,而真机可能会因为种种原因导致 node.js 的版本不一样(尤其是在版本更迭极快的今天)。同时 docker 也能一键解决依赖问题。所以还是更加推荐 docker 部署。

顺便附上一个我用的部署命令行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/usr/bin/docker-compose stop
if [ $? -ne 0 ];then
echo -e "${red} 停止旧容器失败 ${font}"
fi

#删除所有(停止状态的)服务容器和镜像,为了保证重新拉取镜像
/usr/bin/docker system prune -a -f
if [ $? -ne 0 ];then
echo -e "${red} 删除旧容器失败 ${font}"
fi

/usr/bin/docker-compose up -d --build
if [ $? -ne 0 ];then
echo -e "${red} 启动新容器失败 ${font}"
fi

本文作者:草梅友仁
本文地址: https://blog.cmyr.ltd/archives/5a4ebd1.html
版权声明:转载请注明出处!

坚持原创技术分享,您的支持将鼓励我继续创作!